@likec4/diagram 1.36.0 → 1.37.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 (183) hide show
  1. package/bundle/{chunk-7MPUJFHj.js → chunk-DSORWspW.js} +1011 -983
  2. package/bundle/custom.js +64 -56
  3. package/bundle/index.js +3546 -3321
  4. package/dist/LikeC4Diagram.props.d.ts +5 -5
  5. package/dist/LikeC4Styles.js +17 -15
  6. package/dist/StaticLikeC4Diagram.d.ts +1 -1
  7. package/dist/StaticLikeC4Diagram.js +3 -0
  8. package/dist/base/BaseXYFlow.d.ts +1 -1
  9. package/dist/base/BaseXYFlow.js +25 -27
  10. package/dist/base/const.d.ts +4 -4
  11. package/dist/base/const.js +5 -4
  12. package/dist/base/primitives/MarkdownBlock.js +4 -1
  13. package/dist/base/primitives/compound/CompoundActionButton.js +27 -42
  14. package/dist/base/primitives/compound/CompoundDetailsButton.js +23 -48
  15. package/dist/base/primitives/compound/CompoundNodeContainer.js +16 -48
  16. package/dist/base/primitives/compound/CompoundTitle.js +5 -80
  17. package/dist/base/primitives/compound/actionbtns.css.js +1 -13
  18. package/dist/base/primitives/customEdge.d.ts +1 -1
  19. package/dist/base/primitives/customNode.d.ts +4 -4
  20. package/dist/base/primitives/customNode.js +7 -7
  21. package/dist/base/primitives/edge/EdgeLabel.d.ts +5 -4
  22. package/dist/base/primitives/edge/EdgeLabel.js +39 -21
  23. package/dist/base/primitives/edge/EdgeLabelContainer.js +11 -23
  24. package/dist/base/primitives/edge/edge.css.js +19 -11
  25. package/dist/base/primitives/element/ElementShape.js +38 -18
  26. package/dist/base/primitives/element/ElementTags.js +7 -4
  27. package/dist/base/primitives/element/ElementTitle.js +10 -2
  28. package/dist/base/types.d.ts +17 -21
  29. package/dist/bundle/LikeC4View.d.ts +2 -2
  30. package/dist/bundle/LikeC4View.js +4 -1
  31. package/dist/bundle/LikeC4View.props.d.ts +2 -2
  32. package/dist/bundle/ReactLikeC4.d.ts +3 -3
  33. package/dist/bundle/custom.js +2 -1
  34. package/dist/bundle/index.js +2 -1
  35. package/dist/components/Link.js +3 -2
  36. package/dist/context/ReduceGraphics.js +2 -5
  37. package/dist/context/RootContainer.js +1 -5
  38. package/dist/custom/customNodes.d.ts +32 -26
  39. package/dist/custom/customNodes.js +12 -8
  40. package/dist/custom/hooks.d.ts +2 -1
  41. package/dist/custom/index.js +2 -1
  42. package/dist/globals.css.js +1 -1
  43. package/dist/hooks/index.d.ts +1 -1
  44. package/dist/hooks/useDiagram.d.ts +18 -1
  45. package/dist/hooks/useDiagram.js +18 -2
  46. package/dist/hooks/useXYFlow.d.ts +40 -21
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.js +2 -1
  49. package/dist/likec4diagram/DiagramUI.js +7 -3
  50. package/dist/likec4diagram/DiagramXYFlow.js +9 -9
  51. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +3 -3
  52. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +27 -44
  53. package/dist/likec4diagram/custom/index.js +3 -3
  54. package/dist/likec4diagram/custom/nodes/nodes.d.ts +8 -6
  55. package/dist/likec4diagram/custom/nodes/nodes.js +13 -14
  56. package/dist/likec4diagram/custom/nodes/toolbar/CompoundToolbar.js +3 -2
  57. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +2 -2
  58. package/dist/likec4diagram/relationship-popover/RelationshipPopover.d.ts +2 -0
  59. package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +441 -0
  60. package/dist/likec4diagram/relationship-popover/actor.d.ts +177 -0
  61. package/dist/likec4diagram/relationship-popover/actor.js +155 -0
  62. package/dist/likec4diagram/relationship-popover/styles.css.d.ts +2 -0
  63. package/dist/likec4diagram/{custom/edges/RelationshipsDropdownMenu.css.js → relationship-popover/styles.css.js} +4 -17
  64. package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +4 -4
  65. package/dist/likec4diagram/useLayoutConstraints.js +0 -1
  66. package/dist/likec4model/LikeC4ModelContext.d.ts +2 -1
  67. package/dist/likec4model/LikeC4ModelContext.js +10 -2
  68. package/dist/likec4model/useCurrentViewModel.d.ts +1 -0
  69. package/dist/likec4model/useCurrentViewModel.js +4 -1
  70. package/dist/likec4model/useLikeC4ElementsTree.js +1 -1
  71. package/dist/likec4model/useLikeC4Project.js +15 -1
  72. package/dist/navigationpanel/NavigationPanelDropdown.js +1 -2
  73. package/dist/navigationpanel/actor.js +1 -2
  74. package/dist/navigationpanel/controls/NavigationButtons.js +1 -5
  75. package/dist/navigationpanel/controls/OpenSource.js +1 -1
  76. package/dist/navigationpanel/controls/ViewDetailsCard.js +2 -0
  77. package/dist/overlays/element-details/actor.d.ts +564 -8
  78. package/dist/overlays/overlay/Overlay.css.d.ts +1 -1
  79. package/dist/overlays/relationship-details/actor.d.ts +3 -1
  80. package/dist/overlays/relationship-details/hooks.d.ts +19 -1
  81. package/dist/overlays/relationship-details/layout-to-xyflow.js +0 -1
  82. package/dist/overlays/relationship-details/layout.js +1 -2
  83. package/dist/overlays/relationships-browser/actor.d.ts +26 -2
  84. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +16 -0
  85. package/dist/overlays/relationships-browser/custom/nodeTypes.js +18 -8
  86. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +0 -1
  87. package/dist/search/components/_shared.css.d.ts +1 -1
  88. package/dist/state/DiagramActorProvider.js +5 -23
  89. package/dist/state/assign.js +24 -10
  90. package/dist/state/diagram-machine.d.ts +149 -474
  91. package/dist/state/diagram-machine.js +94 -54
  92. package/dist/state/types.d.ts +1 -1
  93. package/dist/styles-min.css +1 -1
  94. package/dist/styles-xyflow.css +1 -1
  95. package/dist/styles.css +1 -1
  96. package/dist/styles.css2.js +1 -1
  97. package/dist/utils/index.d.ts +2 -1
  98. package/dist/utils/roundDpr.d.ts +1 -0
  99. package/dist/utils/roundDpr.js +20 -0
  100. package/dist/utils/xyflow.d.ts +0 -1
  101. package/dist/utils/xyflow.js +1 -7
  102. package/package.json +11 -10
  103. package/panda.buildinfo.json +90 -155
  104. package/src/LikeC4Diagram.props.ts +5 -5
  105. package/src/LikeC4Styles.tsx +22 -14
  106. package/src/StaticLikeC4Diagram.tsx +3 -0
  107. package/src/base/BaseXYFlow.tsx +26 -29
  108. package/src/base/const.ts +5 -4
  109. package/src/base/primitives/MarkdownBlock.tsx +6 -1
  110. package/src/base/primitives/compound/CompoundActionButton.tsx +31 -43
  111. package/src/base/primitives/compound/CompoundDetailsButton.tsx +26 -48
  112. package/src/base/primitives/compound/CompoundNodeContainer.tsx +15 -43
  113. package/src/base/primitives/compound/CompoundTitle.tsx +4 -76
  114. package/src/base/primitives/compound/actionbtns.css.ts +0 -12
  115. package/src/base/primitives/customEdge.ts +1 -1
  116. package/src/base/primitives/customNode.tsx +20 -24
  117. package/src/base/primitives/edge/EdgeLabel.tsx +23 -8
  118. package/src/base/primitives/edge/EdgeLabelContainer.tsx +9 -21
  119. package/src/base/primitives/edge/edge.css.ts +19 -11
  120. package/src/base/primitives/element/ElementShape.tsx +40 -18
  121. package/src/base/primitives/element/ElementTags.tsx +7 -4
  122. package/src/base/primitives/element/ElementTitle.tsx +23 -11
  123. package/src/base/types.ts +21 -25
  124. package/src/bundle/LikeC4View.props.ts +2 -2
  125. package/src/bundle/LikeC4View.tsx +8 -5
  126. package/src/bundle/ReactLikeC4.tsx +3 -3
  127. package/src/components/Link.tsx +3 -2
  128. package/src/context/RootContainer.tsx +1 -5
  129. package/src/context/TagStylesContext.tsx +2 -0
  130. package/src/custom/{customNodes.tsx → customNodes.ts} +58 -52
  131. package/src/custom/hooks.ts +7 -0
  132. package/src/globals.css +58 -5
  133. package/src/hooks/index.ts +1 -1
  134. package/src/hooks/useDiagram.ts +39 -5
  135. package/src/hooks/useXYFlow.ts +3 -1
  136. package/src/index.ts +1 -0
  137. package/src/likec4diagram/DiagramUI.tsx +11 -2
  138. package/src/likec4diagram/DiagramXYFlow.tsx +9 -11
  139. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +25 -49
  140. package/src/likec4diagram/custom/index.ts +5 -4
  141. package/src/likec4diagram/custom/nodes/nodes.tsx +13 -11
  142. package/src/likec4diagram/custom/nodes/toolbar/CompoundToolbar.tsx +3 -2
  143. package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +535 -0
  144. package/src/likec4diagram/relationship-popover/actor.ts +192 -0
  145. package/src/likec4diagram/{custom/edges/RelationshipsDropdownMenu.css.ts → relationship-popover/styles.css.ts} +3 -19
  146. package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +4 -5
  147. package/src/likec4diagram/useLayoutConstraints.ts +0 -1
  148. package/src/likec4model/{LikeC4ModelContext.ts → LikeC4ModelContext.tsx} +9 -1
  149. package/src/likec4model/useCurrentViewModel.ts +4 -0
  150. package/src/likec4model/useLikeC4ElementsTree.ts +1 -1
  151. package/src/navigationpanel/NavigationPanelDropdown.tsx +1 -2
  152. package/src/navigationpanel/actor.ts +2 -2
  153. package/src/navigationpanel/controls/NavigationButtons.tsx +1 -5
  154. package/src/navigationpanel/controls/OpenSource.tsx +1 -1
  155. package/src/navigationpanel/controls/ViewDetailsCard.tsx +2 -0
  156. package/src/overlays/relationship-details/layout-to-xyflow.ts +0 -1
  157. package/src/overlays/relationship-details/layout.ts +4 -3
  158. package/src/overlays/relationships-browser/custom/nodeTypes.tsx +22 -8
  159. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +0 -1
  160. package/src/state/DiagramActorProvider.tsx +8 -25
  161. package/src/state/assign.ts +24 -10
  162. package/src/state/diagram-machine.ts +101 -53
  163. package/src/state/types.ts +4 -1
  164. package/src/utils/index.ts +2 -1
  165. package/src/utils/roundDpr.ts +27 -0
  166. package/src/utils/xyflow.ts +0 -7
  167. package/dist/base/primitives/compound/CompoundNodeContainer.css.d.ts +0 -35
  168. package/dist/base/primitives/compound/CompoundNodeContainer.css.js +0 -132
  169. package/dist/base/primitives/edge/EdgeLabel.css.d.ts +0 -7
  170. package/dist/base/primitives/edge/EdgeLabel.css.js +0 -57
  171. package/dist/base/primitives/element/ElementShape.css.d.ts +0 -6
  172. package/dist/base/primitives/element/ElementShape.css.js +0 -107
  173. package/dist/likec4diagram/custom/edges/NotePopover.css.js +0 -21
  174. package/dist/likec4diagram/custom/edges/NotePopover.js +0 -91
  175. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.css.d.ts +0 -5
  176. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.d.ts +0 -13
  177. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +0 -215
  178. package/dist/likec4diagram/custom/index.d.ts +0 -62
  179. package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +0 -10
  180. package/src/base/primitives/compound/CompoundNodeContainer.css.ts +0 -138
  181. package/src/base/primitives/edge/EdgeLabel.css.ts +0 -64
  182. package/src/base/primitives/element/ElementShape.css.ts +0 -112
  183. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +0 -281
@@ -0,0 +1,192 @@
1
+ import { type EdgeId } from '@likec4/core/types'
2
+ import {
3
+ type ActorLogicFrom,
4
+ type ActorRefFrom,
5
+ type SnapshotFrom,
6
+ assertEvent,
7
+ assign,
8
+ setup,
9
+ } from 'xstate'
10
+
11
+ export type RelationshipPopoverActorEvent =
12
+ // Events from the UI
13
+ | { type: 'xyedge.mouseEnter'; edgeId: EdgeId }
14
+ | { type: 'xyedge.mouseLeave' }
15
+ | { type: 'xyedge.select'; edgeId: EdgeId }
16
+ | { type: 'xyedge.unselect' }
17
+ | { type: 'close' }
18
+ // - From dropdown
19
+ | { type: 'dropdown.mouseEnter' }
20
+ | { type: 'dropdown.mouseLeave' }
21
+
22
+ export interface RelationshipPopoverActorContext {
23
+ edgeId: EdgeId | null
24
+ /**
25
+ * True if the edge was selected
26
+ */
27
+ edgeSelected: boolean
28
+
29
+ /**
30
+ * The timeout for opening the popover
31
+ * If it was closed recently (<1.5s), it will be 300ms
32
+ * Otherwise, it will be 800ms
33
+ */
34
+ openTimeout: number
35
+ }
36
+
37
+ const _actorLogic = setup({
38
+ types: {
39
+ context: {} as RelationshipPopoverActorContext,
40
+ events: {} as RelationshipPopoverActorEvent,
41
+ tags: 'opened',
42
+ },
43
+ delays: {
44
+ 'open timeout': ({ context }) => context.openTimeout,
45
+ 'close timeout': 600,
46
+ 'long idle': 1500,
47
+ },
48
+ actions: {
49
+ 'update edgeId': assign(({ context, event }) => {
50
+ assertEvent(event, ['xyedge.select', 'xyedge.mouseEnter'])
51
+ return {
52
+ edgeId: event.edgeId,
53
+ edgeSelected: context.edgeSelected || event.type === 'xyedge.select',
54
+ }
55
+ }),
56
+ 'increase open timeout': assign(() => ({
57
+ openTimeout: 800,
58
+ })),
59
+ 'decrease open timeout': assign(() => ({
60
+ openTimeout: 300,
61
+ })),
62
+ 'reset edgeId': assign({
63
+ edgeId: null,
64
+ edgeSelected: false,
65
+ }),
66
+ },
67
+ guards: {
68
+ 'edge was selected': ({ context }) => context.edgeSelected,
69
+ 'edge was hovered': ({ context }) => !context.edgeSelected,
70
+ },
71
+ }).createMachine({
72
+ id: 'breadcrumbs',
73
+ context: () => ({
74
+ edgeId: null,
75
+ edgeSelected: false,
76
+ openTimeout: 800,
77
+ }),
78
+ initial: 'idle',
79
+ on: {
80
+ 'close': {
81
+ target: '#idle',
82
+ actions: [
83
+ 'reset edgeId',
84
+ 'increase open timeout',
85
+ ],
86
+ },
87
+ },
88
+ states: {
89
+ idle: {
90
+ id: 'idle',
91
+ on: {
92
+ 'xyedge.mouseEnter': {
93
+ target: 'opening',
94
+ actions: 'update edgeId',
95
+ },
96
+ 'xyedge.select': {
97
+ target: 'active',
98
+ actions: 'update edgeId',
99
+ },
100
+ },
101
+ after: {
102
+ 'long idle': {
103
+ actions: 'increase open timeout',
104
+ },
105
+ },
106
+ },
107
+ opening: {
108
+ on: {
109
+ 'xyedge.mouseLeave': {
110
+ target: 'idle',
111
+ },
112
+ 'xyedge.select': {
113
+ target: 'active',
114
+ actions: 'update edgeId',
115
+ },
116
+ },
117
+ after: {
118
+ 'open timeout': {
119
+ actions: 'decrease open timeout',
120
+ target: 'active',
121
+ },
122
+ },
123
+ },
124
+ active: {
125
+ tags: ['opened'],
126
+ initial: 'opened',
127
+ exit: 'reset edgeId',
128
+ on: {
129
+ 'xyedge.unselect': {
130
+ target: 'idle',
131
+ actions: 'increase open timeout',
132
+ },
133
+ 'xyedge.select': {
134
+ actions: 'update edgeId',
135
+ },
136
+ },
137
+ states: {
138
+ opened: {
139
+ on: {
140
+ 'dropdown.mouseEnter': {
141
+ target: 'hovered',
142
+ },
143
+ 'xyedge.mouseLeave': {
144
+ guard: 'edge was hovered',
145
+ target: 'closing',
146
+ },
147
+ },
148
+ },
149
+ hovered: {
150
+ on: {
151
+ 'dropdown.mouseLeave': [
152
+ {
153
+ guard: 'edge was selected',
154
+ target: 'opened',
155
+ },
156
+ {
157
+ target: 'closing',
158
+ },
159
+ ],
160
+ },
161
+ },
162
+ closing: {
163
+ on: {
164
+ 'xyedge.mouseEnter': {
165
+ guard: 'edge was hovered',
166
+ target: 'opened',
167
+ actions: 'update edgeId',
168
+ },
169
+ 'xyedge.select': {
170
+ target: 'opened',
171
+ actions: 'update edgeId',
172
+ },
173
+ 'dropdown.mouseEnter': {
174
+ target: 'hovered',
175
+ },
176
+ },
177
+ after: {
178
+ 'close timeout': {
179
+ target: '#idle',
180
+ },
181
+ },
182
+ },
183
+ },
184
+ },
185
+ },
186
+ })
187
+
188
+ export interface RelationshipPopoverActorLogic extends ActorLogicFrom<typeof _actorLogic> {}
189
+ export const RelationshipPopoverActorLogic: RelationshipPopoverActorLogic = _actorLogic
190
+
191
+ export type RelationshipPopoverActorSnapshot = SnapshotFrom<RelationshipPopoverActorLogic>
192
+ export interface RelationshipPopoverActorRef extends ActorRefFrom<RelationshipPopoverActorLogic> {}
@@ -1,15 +1,5 @@
1
1
  import { css } from '@likec4/styles/css'
2
2
 
3
- export const menuDropdown = css({
4
- overflowY: 'scroll',
5
- minWidth: '250px',
6
- maxWidth: 'min(90vw, 500px)',
7
- })
8
-
9
- export const menuItemRelationship = css({
10
- gap: '1',
11
- })
12
-
13
3
  export const endpoint = css({
14
4
  display: 'block',
15
5
  fontSize: 'xxs',
@@ -24,17 +14,11 @@ export const endpoint = css({
24
14
  _light: `[color-mix(in srgb, var(--likec4-palette-stroke), {colors.likec4.mixColor} 60%)]`,
25
15
  _dark: 'var(--likec4-palette-loContrast)',
26
16
  },
27
- // _dark: {
28
- // background: `var(--likec4-palette-fill)/60`,
29
- // },
30
17
  })
31
18
 
32
19
  export const title = css({
33
20
  whiteSpaceCollapse: 'preserve-breaks',
34
- fontSize: 'xs',
35
- })
36
-
37
- export const arrowFromTo = css({
38
- whiteSpaceCollapse: 'preserve-breaks',
39
- fontSize: 'xs',
21
+ fontSize: 'sm',
22
+ lineHeight: 'sm',
23
+ userSelect: 'all',
40
24
  })
@@ -1,4 +1,3 @@
1
- import { RichText } from '@likec4/core/types'
2
1
  import { cx as clsx } from '@likec4/styles/css'
3
2
  import { Button, Card, CardSection, Group, Spoiler, Stack, Text } from '@mantine/core'
4
3
  import { useLocalStorage } from '@mantine/hooks'
@@ -7,7 +6,7 @@ import { AnimatePresence, m } from 'motion/react'
7
6
  import { MarkdownBlock } from '../../../base/primitives'
8
7
  import { Link } from '../../../components/Link'
9
8
  import { useDiagramContext } from '../../../hooks/useDiagram'
10
- import { useCurrentViewModel } from '../../../likec4model'
9
+ import { useOptionalCurrentViewModel } from '../../../likec4model/useCurrentViewModel'
11
10
  import type { DiagramContext } from '../../../state/types'
12
11
  import * as styles from './DiagramTitlePanel.css'
13
12
 
@@ -22,13 +21,13 @@ function selector(context: DiagramContext) {
22
21
  }
23
22
 
24
23
  export function DiagramTitlePanel() {
25
- const view = useCurrentViewModel()
24
+ const view = useOptionalCurrentViewModel()
26
25
  const { isNotActiveWalkthrough } = useDiagramContext(selector)
27
26
  const [isCollapsed, setCollapsed] = useLocalStorage({
28
27
  key: 'diagram-title-webview-collapsed',
29
28
  defaultValue: false,
30
29
  })
31
- const title = view.title ?? 'untitled'
30
+ const title = view?.title ?? 'untitled'
32
31
  const toggle = () => setCollapsed(v => !v)
33
32
 
34
33
  return (
@@ -49,7 +48,7 @@ export function DiagramTitlePanel() {
49
48
  </div>
50
49
  </ViewportPortal> */
51
50
  }
52
- {isNotActiveWalkthrough && (
51
+ {view && isNotActiveWalkthrough && (
53
52
  <m.div
54
53
  initial={{ opacity: 0.05, scale: 0.7 }}
55
54
  animate={{ opacity: 1, scale: 1 }}
@@ -271,7 +271,6 @@ export function useLayoutConstraints(): LayoutConstraints {
271
271
  },
272
272
  onNodeDragStop: (_event) => {
273
273
  moved = Math.abs(_event.clientX - initial.x) > 4 || Math.abs(_event.clientY - initial.y) > 4
274
- console.log('moved', moved)
275
274
  if (wasPending || moved) {
276
275
  diagram.scheduleSaveManualLayout()
277
276
  }
@@ -1,8 +1,16 @@
1
1
  import type { LikeC4Model, LikeC4ViewModel } from '@likec4/core/model'
2
2
  import type { aux, DiagramView } from '@likec4/core/types'
3
- import { createContext } from 'react'
3
+ import { type PropsWithChildren, createContext, useContext } from 'react'
4
4
 
5
5
  export const LikeC4ModelContext = createContext<LikeC4Model<any> | null>(null)
6
6
 
7
7
  export type CurrentViewModel = LikeC4ViewModel<aux.UnknownLayouted, DiagramView<aux.UnknownLayouted>>
8
8
  export const CurrentViewModelContext = createContext<CurrentViewModel | null>(null)
9
+
10
+ export function EnsureCurrentViewModel({ children }: PropsWithChildren) {
11
+ const viewmodel = useContext(CurrentViewModelContext)
12
+ if (!viewmodel) {
13
+ return null
14
+ }
15
+ return <>{children}</>
16
+ }
@@ -1,6 +1,10 @@
1
1
  import { useContext } from 'react'
2
2
  import { type CurrentViewModel, CurrentViewModelContext } from './LikeC4ModelContext'
3
3
 
4
+ export function useOptionalCurrentViewModel(): CurrentViewModel | null {
5
+ return useContext(CurrentViewModelContext)
6
+ }
7
+
4
8
  export function useCurrentViewModel(): CurrentViewModel {
5
9
  const vm = useContext(CurrentViewModelContext)
6
10
  if (!vm) {
@@ -1,6 +1,6 @@
1
+ import { compareNatural } from '@likec4/core'
1
2
  import { type LikeC4Model } from '@likec4/core/model'
2
3
  import { type Fqn, type ViewId } from '@likec4/core/types'
3
- import { compareNatural } from '@likec4/core/utils'
4
4
  import { useMemo } from 'react'
5
5
  import { useLikeC4Model } from './useLikeC4Model'
6
6
 
@@ -1,6 +1,6 @@
1
+ import { compareNaturalHierarchically, ifilter, ifirst, nonexhaustive, toArray } from '@likec4/core'
1
2
  import { type LikeC4ViewsFolder, LikeC4ViewModel, normalizeViewPath, VIEW_FOLDERS_SEPARATOR } from '@likec4/core/model'
2
3
  import type { ViewId } from '@likec4/core/types'
3
- import { compareNaturalHierarchically, ifilter, ifirst, nonexhaustive, toArray } from '@likec4/core/utils'
4
4
  import { css, cx } from '@likec4/styles/css'
5
5
  import { Box, HStack, VStack } from '@likec4/styles/jsx'
6
6
  import { hstack, vstack } from '@likec4/styles/patterns'
@@ -155,7 +155,6 @@ function SearchResults({ searchQuery }: { searchQuery: string }) {
155
155
  view={v}
156
156
  highlight={highlight}
157
157
  onClick={e => {
158
- console.log('click')
159
158
  e.stopPropagation()
160
159
  actor.selectView(v.id)
161
160
  }}
@@ -1,4 +1,4 @@
1
- import { ViewId } from '@likec4/core/types'
1
+ import type { ViewId } from '@likec4/core/types'
2
2
  import { isEmpty } from 'remeda'
3
3
  import {
4
4
  type ActorLogicFrom,
@@ -143,7 +143,7 @@ const _actorLogic = setup({
143
143
  assertEvent(event, 'select.view')
144
144
  return {
145
145
  type: 'navigateTo' as const,
146
- viewId: ViewId(event.viewId),
146
+ viewId: event.viewId,
147
147
  }
148
148
  }),
149
149
  },
@@ -17,11 +17,7 @@ export const NavigationButtons = () => {
17
17
  <m.div
18
18
  layout="position"
19
19
  className={hstack({
20
- gap: '[1px]',
21
- display: {
22
- base: 'none',
23
- '@likec4-root/sm': 'flex',
24
- },
20
+ gap: '0.5',
25
21
  })}>
26
22
  <PanelActionIcon
27
23
  disabled={!hasStepBack}
@@ -21,7 +21,7 @@ export const OpenSource = () => {
21
21
  e.stopPropagation()
22
22
  onOpenSource?.({ view: viewId })
23
23
  }}
24
- children={<IconFileSymlink stroke={1.5} style={{ width: '65%' }} />}
24
+ children={<IconFileSymlink style={{ width: '60%', height: '60%' }} />}
25
25
  />
26
26
  </Tooltip>
27
27
  )
@@ -137,6 +137,8 @@ const ViewDetailsCardDropdown = ({
137
137
  maxHeight: 'calc(100cqh - 100px)',
138
138
  width: 'max-content',
139
139
  cursor: 'default',
140
+ overflow: 'auto',
141
+ overscrollBehavior: 'contain',
140
142
  '@/sm': {
141
143
  minWidth: 400,
142
144
  maxWidth: 550,
@@ -150,7 +150,6 @@ export function layoutResultToXYFlow(
150
150
  target: ns + target,
151
151
  sourceHandle: edge.sourceHandle,
152
152
  targetHandle: edge.targetHandle,
153
- zIndex: ZIndexes.Edge,
154
153
  // selectable: selectable,
155
154
  // hidden: !visiblePredicate(edge),
156
155
  deletable: false,
@@ -16,12 +16,13 @@ import type {
16
16
  } from '@likec4/core/types'
17
17
 
18
18
  import dagre, { type EdgeConfig, type GraphLabel } from '@dagrejs/dagre'
19
- import { invariant, RichText } from '@likec4/core'
20
- import type { AnyAux, ElementModel, LikeC4ViewModel, RelationshipModel } from '@likec4/core/model'
21
19
  import {
22
20
  DefaultMap,
23
21
  ifind,
24
- } from '@likec4/core/utils'
22
+ invariant,
23
+ RichText,
24
+ } from '@likec4/core'
25
+ import type { AnyAux, ElementModel, LikeC4ViewModel, RelationshipModel } from '@likec4/core/model'
25
26
  import {
26
27
  filter,
27
28
  find,
@@ -1,10 +1,11 @@
1
1
  import { Handle } from '@xyflow/react'
2
2
  import { Position } from '@xyflow/system'
3
+ import type { FC } from 'react'
3
4
  import type { NodeProps } from '../../../base'
4
5
  import {
6
+ CompoundDetailsButton,
5
7
  CompoundNodeContainer,
6
8
  CompoundTitle,
7
- customNode,
8
9
  ElementDetailsButton,
9
10
  ElementNodeContainer,
10
11
  ElementShape,
@@ -17,6 +18,12 @@ import type { RelationshipsBrowserTypes } from '../_types'
17
18
  import { ElementActions } from './ElementActions'
18
19
  import { EmptyNode as EmptyNodeRender } from './EmptyNode'
19
20
 
21
+ type NodeTypes = {
22
+ element: FC<NodeProps<RelationshipsBrowserTypes.ElementNodeData>>
23
+ compound: FC<NodeProps<RelationshipsBrowserTypes.CompoundNodeData>>
24
+ empty: FC<NodeProps<RelationshipsBrowserTypes.EmptyNodeData>>
25
+ }
26
+
20
27
  const ElementDetailsButtonWithHandler = (
21
28
  props: NodeProps<RelationshipsBrowserTypes.ElementNodeData | RelationshipsBrowserTypes.CompoundNodeData>,
22
29
  ) => {
@@ -33,7 +40,7 @@ const ElementDetailsButtonWithHandler = (
33
40
  )
34
41
  }
35
42
 
36
- export const ElementNode = customNode<RelationshipsBrowserTypes.ElementNodeData>((props) => {
43
+ export const ElementNode: NodeTypes['element'] = (props) => {
37
44
  const { enableElementTags } = useEnabledFeatures()
38
45
  return (
39
46
  <ElementNodeContainer key={props.id} layoutId={props.id} nodeProps={props}>
@@ -45,21 +52,28 @@ export const ElementNode = customNode<RelationshipsBrowserTypes.ElementNodeData>
45
52
  <ElementPorts {...props} />
46
53
  </ElementNodeContainer>
47
54
  )
48
- })
55
+ }
49
56
 
50
- export const CompoundNode = customNode<RelationshipsBrowserTypes.CompoundNodeData>((props) => {
57
+ export const CompoundNode: NodeTypes['compound'] = (props) => {
58
+ const diagram = useDiagram()
51
59
  return (
52
60
  <CompoundNodeContainer key={props.id} layoutId={props.id} nodeProps={props}>
53
- <ElementDetailsButtonWithHandler {...props} />
54
61
  <CompoundTitle {...props} />
62
+ <CompoundDetailsButton
63
+ {...props}
64
+ onClick={e => {
65
+ e.stopPropagation()
66
+ diagram.openElementDetails(props.data.fqn)
67
+ }}
68
+ />
55
69
  <CompoundPorts {...props} />
56
70
  </CompoundNodeContainer>
57
71
  )
58
- })
72
+ }
59
73
 
60
- export const EmptyNode = customNode<RelationshipsBrowserTypes.EmptyNodeData>((props) => {
74
+ export const EmptyNode: NodeTypes['empty'] = (props) => {
61
75
  return <EmptyNodeRender {...props} />
62
- })
76
+ }
63
77
 
64
78
  type ElementPortsProps = NodeProps<
65
79
  Pick<
@@ -177,7 +177,6 @@ export function viewToNodesEdge(
177
177
  target: ns + target,
178
178
  sourceHandle: edge.sourceHandle,
179
179
  targetHandle: edge.targetHandle,
180
- zIndex: ZIndexes.Edge,
181
180
  // selectable: selectable,
182
181
  // hidden: !visiblePredicate(edge),
183
182
  // deletable: false,
@@ -1,14 +1,13 @@
1
- import type { DiagramView, WhereOperator } from '@likec4/core/types'
1
+ import type { DiagramView, ViewId, WhereOperator } from '@likec4/core/types'
2
2
  import { useCustomCompareEffect } 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, useState } from 'react'
6
+ import { type PropsWithChildren, useEffect, 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 { DiagramActorContextProvider } from '../hooks/safeContext'
11
- import { useCurrentViewId } from '../hooks/useCurrentViewId'
12
11
  import type { ViewPadding } from '../LikeC4Diagram.props'
13
12
  import type { Types } from '../likec4diagram/types'
14
13
  import { useViewToNodesEdges } from '../likec4diagram/useViewToNodesEdges'
@@ -114,7 +113,7 @@ export function DiagramActorProvider({
114
113
  <DiagramActorContextProvider value={actorRef}>
115
114
  <DiagramFeatures overrides={toggledFeatures}>
116
115
  <ErrorBoundary>
117
- <CurrentViewModelProvider>
116
+ <CurrentViewModelProvider viewId={view.id}>
118
117
  {children}
119
118
  </CurrentViewModelProvider>
120
119
  </ErrorBoundary>
@@ -125,28 +124,12 @@ export function DiagramActorProvider({
125
124
 
126
125
  function CurrentViewModelProvider({
127
126
  children,
128
- }: PropsWithChildren) {
129
- const viewId = useCurrentViewId()
127
+ viewId,
128
+ }: PropsWithChildren<{
129
+ viewId: ViewId
130
+ }>) {
130
131
  const likec4model = useLikeC4Model()
131
- const [viewmodel, setViewmodel] = useState(() => likec4model.view(viewId))
132
-
133
- useEffect(() => {
134
- setViewmodel(current => {
135
- const nextviewmodel = likec4model.findView(viewId)
136
- if (!nextviewmodel) {
137
- console.error(`View "${viewId}" not found in likec4model, current viewmodel: ${current.id}`, {
138
- currentViewModel: current,
139
- likec4model,
140
- })
141
- return current
142
- }
143
- return nextviewmodel
144
- })
145
- }, [likec4model, viewId])
146
-
147
- if (!viewmodel.isDiagram()) {
148
- console.warn(`View "${viewId}" is not diagram.\nMake sure you have LikeC4ModelProvider with layouted model.`)
149
- }
132
+ const viewmodel = likec4model.findView(viewId)
150
133
  return (
151
134
  <CurrentViewModelContext.Provider value={viewmodel}>
152
135
  {children}
@@ -277,23 +277,37 @@ export function navigateForward({ context }: ActionArg): Partial<DiagramContext>
277
277
 
278
278
  export function updateNodeData({ context, event }: ActionArg): Partial<DiagramContext> {
279
279
  assertEvent(event, 'update.nodeData')
280
- const xynodes = context.xynodes.map((node): Types.Node =>
281
- node.id !== event.nodeId ? node : (({
280
+ const xynodes = context.xynodes.map((node): Types.Node => {
281
+ if (node.id !== event.nodeId) {
282
+ return node
283
+ }
284
+ const data = mergeDeep(node.data as any, event.data as any)
285
+ if (eq(data, node.data)) {
286
+ return node
287
+ }
288
+ return {
282
289
  ...node,
283
- data: mergeDeep(node.data as any, event.data as any),
284
- }) as Types.Node)
285
- )
290
+ data,
291
+ } as Types.Node
292
+ })
286
293
  return { xynodes }
287
294
  }
288
295
 
289
296
  export function updateEdgeData({ context, event }: ActionArg): Partial<DiagramContext> {
290
297
  assertEvent(event, 'update.edgeData')
291
- const xyedges = context.xyedges.map((edge): Types.Edge =>
292
- edge.id !== event.edgeId ? edge : (({
298
+ const xyedges = context.xyedges.map((edge): Types.Edge => {
299
+ if (edge.id !== event.edgeId) {
300
+ return edge
301
+ }
302
+ const data = mergeDeep(edge.data as any, event.data as any)
303
+ if (eq(data, edge.data)) {
304
+ return edge
305
+ }
306
+ return {
293
307
  ...edge,
294
- data: mergeDeep(edge.data as any, event.data as any),
295
- }) as Types.Edge)
296
- )
308
+ data,
309
+ } as Types.Edge
310
+ })
297
311
  return { xyedges }
298
312
  }
299
313