@likec4/diagram 1.31.0 → 1.32.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 (264) hide show
  1. package/bundle/{chunk-BBzMXzCg.js → chunk-BvTQaUYl.js} +1675 -1207
  2. package/bundle/custom.js +50 -47
  3. package/bundle/index.js +2482 -2438
  4. package/dist/LikeC4CustomColors.d.ts +2 -7
  5. package/dist/LikeC4CustomColors.js +17 -6
  6. package/dist/LikeC4Diagram.d.ts +3 -2
  7. package/dist/LikeC4Diagram.js +10 -14
  8. package/dist/LikeC4Diagram.props.d.ts +28 -22
  9. package/dist/LikeC4ModelProvider.d.ts +5 -4
  10. package/dist/StaticLikeC4Diagram.d.ts +3 -2
  11. package/dist/StaticLikeC4Diagram.js +2 -2
  12. package/dist/base/BaseXYFlow.js +5 -5
  13. package/dist/base/const.d.ts +1 -1
  14. package/dist/base/const.js +1 -1
  15. package/dist/base/index.d.ts +2 -1
  16. package/dist/base/primitives/compound/CompoundActionButton.js +2 -1
  17. package/dist/base/primitives/compound/CompoundDetailsButton.js +2 -1
  18. package/dist/base/primitives/compound/CompoundTitle.d.ts +1 -1
  19. package/dist/base/primitives/compound/CompoundTitle.js +2 -1
  20. package/dist/base/primitives/edge/EdgeContainer.d.ts +1 -1
  21. package/dist/base/primitives/edge/EdgeLabel.css.js +1 -0
  22. package/dist/base/primitives/edge/EdgeLabel.d.ts +3 -3
  23. package/dist/base/primitives/edge/EdgeLabel.js +6 -4
  24. package/dist/base/primitives/edge/EdgeLabelContainer.d.ts +1 -1
  25. package/dist/base/primitives/edge/EdgeMarkers.d.ts +1 -1
  26. package/dist/base/primitives/edge/EdgePath.d.ts +1 -1
  27. package/dist/base/primitives/element/ElementActionButtons.js +10 -9
  28. package/dist/base/primitives/element/ElementDetailsButton.js +2 -1
  29. package/dist/base/primitives/element/ElementShape.d.ts +1 -1
  30. package/dist/base/primitives/element/ElementTags.d.ts +14 -0
  31. package/dist/base/primitives/element/ElementTags.js +176 -0
  32. package/dist/base/primitives/element/ElementTitle.d.ts +5 -4
  33. package/dist/base/primitives/element/ElementTitle.js +6 -6
  34. package/dist/base/primitives/index.d.ts +1 -0
  35. package/dist/base/types.Base.d.ts +54 -0
  36. package/dist/base/types.Base.js +48 -0
  37. package/dist/base/types.d.ts +2 -52
  38. package/dist/bundle/LikeC4View.d.ts +2 -1
  39. package/dist/bundle/LikeC4View.js +8 -6
  40. package/dist/bundle/LikeC4View.props.d.ts +15 -4
  41. package/dist/bundle/ReactLikeC4.d.ts +4 -7
  42. package/dist/bundle/ReactLikeC4.js +3 -2
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/components/ErrorFallback.d.ts +2 -0
  45. package/dist/components/ErrorFallback.js +29 -0
  46. package/dist/context/DiagramEventHandlers.d.ts +6 -5
  47. package/dist/context/DiagramFeatures.d.ts +2 -2
  48. package/dist/context/DiagramFeatures.js +3 -31
  49. package/dist/context/EnsureMantine.js +1 -1
  50. package/dist/context/IconRenderer.js +1 -4
  51. package/dist/context/RootContainer.js +5 -1
  52. package/dist/context/TagStylesContext.d.ts +7 -0
  53. package/dist/context/TagStylesContext.js +85 -0
  54. package/dist/custom/components.d.ts +1 -1
  55. package/dist/custom/customNodes.d.ts +27 -17
  56. package/dist/custom/hooks.d.ts +1 -1
  57. package/dist/hooks/index.d.ts +1 -1
  58. package/dist/hooks/useDiagram.d.ts +73 -38
  59. package/dist/hooks/useDiagram.js +7 -3
  60. package/dist/hooks/useMantinePortalProps.d.ts +2 -2
  61. package/dist/hooks/useSearchActor.d.ts +2 -0
  62. package/dist/hooks/useSearchActor.js +10 -0
  63. package/dist/hooks/useUpdateEffect.js +3 -0
  64. package/dist/hooks/useXYFlow.d.ts +39 -37
  65. package/dist/hooks/useXYFlow.js +5 -1
  66. package/dist/index.js +1 -1
  67. package/dist/likec4diagram/DiagramUI.js +7 -2
  68. package/dist/likec4diagram/DiagramXYFlow.d.ts +4 -3
  69. package/dist/likec4diagram/DiagramXYFlow.js +104 -107
  70. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +7 -6
  71. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +8 -0
  72. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +7 -5
  73. package/dist/likec4diagram/custom/index.d.ts +7 -6
  74. package/dist/likec4diagram/custom/nodes/nodes.js +39 -26
  75. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +3 -3
  76. package/dist/likec4diagram/types.d.ts +5 -5
  77. package/dist/likec4diagram/ui/controls/Controls.js +12 -4
  78. package/dist/likec4diagram/ui/notation/NotationPanel.js +1 -1
  79. package/dist/likec4diagram/useViewToNodesEdges.d.ts +5 -3
  80. package/dist/likec4diagram/useViewToNodesEdges.js +20 -30
  81. package/dist/likec4model/LikeC4ModelContext.d.ts +2 -2
  82. package/dist/likec4model/useLikeC4ElementsTree.js +1 -1
  83. package/dist/likec4model/useLikeC4Model.d.ts +22 -10
  84. package/dist/likec4model/useLikeC4Model.js +11 -7
  85. package/dist/overlays/Overlays.js +4 -27
  86. package/dist/overlays/element-details/ElementDetailsCard.d.ts +1 -1
  87. package/dist/overlays/element-details/ElementDetailsCard.js +19 -12
  88. package/dist/overlays/element-details/TabPanelDeployments.d.ts +1 -1
  89. package/dist/overlays/element-details/TabPanelDeployments.js +1 -1
  90. package/dist/overlays/element-details/TabPanelRelationships.d.ts +1 -1
  91. package/dist/overlays/element-details/TabPanelStructure.d.ts +1 -1
  92. package/dist/overlays/element-details/actor.d.ts +288 -286
  93. package/dist/overlays/overlay/Overlay.css.d.ts +57 -2
  94. package/dist/overlays/overlay/Overlay.css.js +76 -39
  95. package/dist/overlays/overlay/Overlay.d.ts +12 -0
  96. package/dist/overlays/overlay/Overlay.js +36 -25
  97. package/dist/overlays/overlaysActor.d.ts +1 -1
  98. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +3 -2
  99. package/dist/overlays/relationship-details/RelationshipDetails.js +3 -3
  100. package/dist/overlays/relationship-details/_types.d.ts +2 -2
  101. package/dist/overlays/relationship-details/actor.js +7 -7
  102. package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +3 -2
  103. package/dist/overlays/relationship-details/custom/nodeTypes.js +4 -0
  104. package/dist/overlays/relationship-details/hooks.d.ts +10 -9
  105. package/dist/overlays/relationship-details/layout-to-xyflow.js +1 -0
  106. package/dist/overlays/relationship-details/layout.js +3 -1
  107. package/dist/overlays/relationships-browser/RelationshipsBrowser.d.ts +3 -2
  108. package/dist/overlays/relationships-browser/SelectElement.js +1 -1
  109. package/dist/overlays/relationships-browser/_types.d.ts +2 -2
  110. package/dist/overlays/relationships-browser/actor.d.ts +1 -1
  111. package/dist/overlays/relationships-browser/actor.js +7 -7
  112. package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -2
  113. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +8 -5
  114. package/dist/overlays/relationships-browser/custom/nodeTypes.js +4 -0
  115. package/dist/overlays/relationships-browser/layout.d.ts +2 -2
  116. package/dist/overlays/relationships-browser/layout.js +10 -6
  117. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +4 -3
  118. package/dist/search/Search.d.ts +5 -0
  119. package/dist/search/Search.js +192 -0
  120. package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.css.js +0 -1
  121. package/dist/search/components/ElementsColumn.d.ts +2 -0
  122. package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.js +21 -19
  123. package/dist/search/components/PickView.d.ts +4 -0
  124. package/dist/search/components/PickView.js +135 -0
  125. package/dist/search/components/SearchByTags.d.ts +1 -0
  126. package/dist/search/components/SearchByTags.js +116 -0
  127. package/dist/search/components/SearchInput.d.ts +2 -0
  128. package/dist/{likec4diagram/ui/search → search/components}/SearchInput.js +53 -34
  129. package/dist/{likec4diagram/ui/search → search/components}/ViewsColum.d.ts +3 -2
  130. package/dist/{likec4diagram/ui/search → search/components}/ViewsColum.js +14 -13
  131. package/dist/{likec4diagram/ui/search → search/components}/_shared.css.js +26 -35
  132. package/dist/{likec4diagram/ui/search/LikeC4Search.css.d.ts → search/components/styles.css.d.ts} +0 -2
  133. package/dist/search/components/styles.css.js +60 -0
  134. package/dist/{likec4diagram/ui/search → search/components}/utils.d.ts +1 -0
  135. package/dist/{likec4diagram/ui/search → search/components}/utils.js +7 -1
  136. package/dist/search/hooks.d.ts +16 -0
  137. package/dist/search/hooks.js +35 -0
  138. package/dist/search/searchActor.d.ts +90 -0
  139. package/dist/search/searchActor.js +75 -0
  140. package/dist/state/DiagramActorProvider.d.ts +9 -7
  141. package/dist/state/DiagramActorProvider.js +24 -18
  142. package/dist/state/assign.d.ts +0 -1
  143. package/dist/state/assign.js +9 -19
  144. package/dist/state/diagram-machine.d.ts +430 -176
  145. package/dist/state/diagram-machine.js +119 -54
  146. package/dist/state/syncManualLayoutActor.d.ts +2 -2
  147. package/dist/state/types.d.ts +2 -0
  148. package/dist/state/utils.d.ts +2 -0
  149. package/dist/state/utils.js +3 -0
  150. package/dist/styles-min.css +1 -1
  151. package/dist/styles-xyflow.css +1 -1
  152. package/dist/styles.css +1 -1
  153. package/dist/styles.css2.js +1 -1
  154. package/package.json +18 -18
  155. package/panda.buildinfo.json +171 -148
  156. package/src/LikeC4CustomColors.tsx +21 -6
  157. package/src/LikeC4Diagram.props.ts +35 -30
  158. package/src/LikeC4Diagram.tsx +19 -20
  159. package/src/LikeC4ModelProvider.tsx +6 -5
  160. package/src/StaticLikeC4Diagram.tsx +8 -6
  161. package/src/base/const.ts +1 -1
  162. package/src/base/index.ts +2 -1
  163. package/src/base/primitives/compound/CompoundActionButton.tsx +2 -1
  164. package/src/base/primitives/compound/CompoundDetailsButton.tsx +2 -1
  165. package/src/base/primitives/compound/CompoundTitle.tsx +3 -2
  166. package/src/base/primitives/edge/EdgeContainer.tsx +2 -1
  167. package/src/base/primitives/edge/EdgeLabel.css.ts +1 -0
  168. package/src/base/primitives/edge/EdgeLabel.tsx +20 -15
  169. package/src/base/primitives/edge/EdgeLabelContainer.tsx +1 -1
  170. package/src/base/primitives/edge/EdgeMarkers.tsx +2 -1
  171. package/src/base/primitives/edge/EdgePath.tsx +1 -1
  172. package/src/base/primitives/element/ElementActionButtons.tsx +11 -10
  173. package/src/base/primitives/element/ElementDetailsButton.tsx +2 -1
  174. package/src/base/primitives/element/ElementShape.tsx +2 -1
  175. package/src/base/primitives/element/ElementTags.tsx +182 -0
  176. package/src/base/primitives/element/ElementTitle.tsx +21 -15
  177. package/src/base/primitives/index.ts +1 -0
  178. package/src/base/types.Base.ts +104 -0
  179. package/src/base/types.ts +2 -99
  180. package/src/bundle/LikeC4View.props.ts +17 -4
  181. package/src/bundle/LikeC4View.tsx +17 -19
  182. package/src/bundle/ReactLikeC4.tsx +14 -26
  183. package/src/components/ErrorFallback.tsx +30 -0
  184. package/src/context/DiagramEventHandlers.tsx +5 -4
  185. package/src/context/DiagramFeatures.tsx +3 -22
  186. package/src/context/EnsureMantine.tsx +1 -1
  187. package/src/context/IconRenderer.tsx +1 -4
  188. package/src/context/RootContainer.tsx +9 -3
  189. package/src/context/TagStylesContext.tsx +96 -0
  190. package/src/custom/components.ts +2 -0
  191. package/src/custom/customNodes.tsx +24 -14
  192. package/src/custom/hooks.ts +1 -0
  193. package/src/hooks/index.ts +1 -1
  194. package/src/hooks/useCurrentViewId.ts +1 -4
  195. package/src/hooks/useDiagram.ts +104 -12
  196. package/src/hooks/useMantinePortalProps.ts +10 -1
  197. package/src/hooks/useSearchActor.ts +11 -0
  198. package/src/hooks/useUpdateEffect.ts +7 -4
  199. package/src/hooks/useXYFlow.ts +5 -0
  200. package/src/likec4diagram/DiagramUI.tsx +5 -0
  201. package/src/likec4diagram/DiagramXYFlow.tsx +115 -118
  202. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +9 -0
  203. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +10 -9
  204. package/src/likec4diagram/custom/nodes/nodes.tsx +45 -43
  205. package/src/likec4diagram/custom/nodes/toolbar/_shared.tsx +11 -3
  206. package/src/likec4diagram/types.ts +5 -3
  207. package/src/likec4diagram/ui/controls/Controls.tsx +11 -4
  208. package/src/likec4diagram/ui/notation/NotationPanel.tsx +2 -2
  209. package/src/likec4diagram/useViewToNodesEdges.ts +34 -36
  210. package/src/likec4model/LikeC4ModelContext.ts +2 -2
  211. package/src/likec4model/useLikeC4ElementsTree.ts +1 -1
  212. package/src/likec4model/useLikeC4Model.ts +18 -16
  213. package/src/overlays/Overlays.tsx +5 -32
  214. package/src/overlays/element-details/ElementDetailsCard.tsx +25 -18
  215. package/src/overlays/element-details/TabPanelDeployments.tsx +3 -2
  216. package/src/overlays/element-details/TabPanelRelationships.tsx +2 -1
  217. package/src/overlays/element-details/TabPanelStructure.tsx +1 -1
  218. package/src/overlays/element-details/actor.ts +2 -2
  219. package/src/overlays/overlay/Overlay.css.ts +75 -38
  220. package/src/overlays/overlay/Overlay.tsx +43 -26
  221. package/src/overlays/overlaysActor.ts +1 -1
  222. package/src/overlays/relationship-details/RelationshipDetails.tsx +4 -4
  223. package/src/overlays/relationship-details/_types.ts +2 -1
  224. package/src/overlays/relationship-details/custom/nodeTypes.tsx +4 -0
  225. package/src/overlays/relationship-details/layout-to-xyflow.ts +1 -0
  226. package/src/overlays/relationship-details/layout.ts +3 -1
  227. package/src/overlays/relationships-browser/SelectElement.tsx +1 -1
  228. package/src/overlays/relationships-browser/_types.ts +2 -1
  229. package/src/overlays/relationships-browser/custom/nodeTypes.tsx +4 -0
  230. package/src/overlays/relationships-browser/layout.ts +12 -7
  231. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +4 -4
  232. package/src/search/Search.tsx +237 -0
  233. package/src/{likec4diagram/ui/search → search/components}/ElementsColumn.css.ts +0 -29
  234. package/src/{likec4diagram/ui/search → search/components}/ElementsColumn.tsx +24 -22
  235. package/src/search/components/PickView.tsx +140 -0
  236. package/src/search/components/SearchByTags.tsx +109 -0
  237. package/src/{likec4diagram/ui/search → search/components}/SearchInput.tsx +63 -36
  238. package/src/{likec4diagram/ui/search → search/components}/ViewsColum.tsx +17 -18
  239. package/src/{likec4diagram/ui/search → search/components}/_shared.css.ts +26 -37
  240. package/src/{likec4diagram/ui/search/LikeC4Search.css.ts → search/components/styles.css.ts} +9 -36
  241. package/src/{likec4diagram/ui/search → search/components}/utils.ts +7 -0
  242. package/src/search/hooks.ts +41 -0
  243. package/src/search/searchActor.ts +99 -0
  244. package/src/state/DiagramActorProvider.tsx +36 -25
  245. package/src/state/assign.ts +10 -10
  246. package/src/state/diagram-machine.ts +115 -52
  247. package/src/state/syncManualLayoutActor.ts +1 -1
  248. package/src/state/types.ts +2 -0
  249. package/src/state/utils.ts +4 -0
  250. package/dist/base/types.js +0 -54
  251. package/dist/likec4diagram/ui/search/ElementsColumn.d.ts +0 -1
  252. package/dist/likec4diagram/ui/search/LikeC4Search.css.js +0 -87
  253. package/dist/likec4diagram/ui/search/LikeC4Search.d.ts +0 -2
  254. package/dist/likec4diagram/ui/search/LikeC4Search.js +0 -267
  255. package/dist/likec4diagram/ui/search/SearchInput.d.ts +0 -1
  256. package/dist/likec4diagram/ui/search/state.d.ts +0 -19
  257. package/dist/likec4diagram/ui/search/state.js +0 -63
  258. package/src/likec4diagram/ui/search/LikeC4Search.tsx +0 -301
  259. package/src/likec4diagram/ui/search/state.ts +0 -78
  260. /package/dist/{likec4diagram/ui/search → search/components}/ElementsColumn.css.d.ts +0 -0
  261. /package/dist/{likec4diagram/ui/search → search/components}/ViewsColumn.css.d.ts +0 -0
  262. /package/dist/{likec4diagram/ui/search → search/components}/ViewsColumn.css.js +0 -0
  263. /package/dist/{likec4diagram/ui/search → search/components}/_shared.css.d.ts +0 -0
  264. /package/src/{likec4diagram/ui/search → search/components}/ViewsColumn.css.ts +0 -0
@@ -1,17 +1,19 @@
1
1
  import {
2
+ type aux,
2
3
  type DiagramEdge,
3
4
  type DiagramNode,
4
5
  type DiagramView,
5
6
  type EdgeId,
6
- type ElementNotation,
7
7
  type Fqn,
8
8
  type NodeId,
9
+ type NodeNotation as ElementNotation,
10
+ type scalar,
9
11
  type ViewId,
10
- } from '@likec4/core'
12
+ } from '@likec4/core/types'
11
13
  import { useCallbackRef } from '@mantine/hooks'
12
14
  import { useSelector as useXstateSelector } from '@xstate/react'
13
15
  import { shallowEqual } from 'fast-equals'
14
- import { useMemo } from 'react'
16
+ import { type DependencyList, useCallback, useMemo } from 'react'
15
17
  import type { PartialDeep } from 'type-fest'
16
18
  import type { FeatureName } from '../context/DiagramFeatures'
17
19
  import type { OpenSourceParams } from '../LikeC4Diagram.props'
@@ -19,6 +21,7 @@ import type { Types } from '../likec4diagram/types'
19
21
  import type { AlignmentMode } from '../state/aligners'
20
22
  import type {
21
23
  DiagramActorEvent,
24
+ DiagramActorRef,
22
25
  DiagramActorSnapshot,
23
26
  DiagramContext,
24
27
  SyncLayoutActorRef,
@@ -29,13 +32,96 @@ import { useDiagramActorRef } from './safeContext'
29
32
 
30
33
  export { useDiagramActorRef }
31
34
 
35
+ export interface DiagramApi {
36
+ readonly actor: DiagramActorRef
37
+ /**
38
+ * @warning Do not use in render phase
39
+ */
40
+ readonly currentView: DiagramView
41
+ /**
42
+ * Send event to diagram actor
43
+ */
44
+ send(event: DiagramActorEvent): void
45
+ /**
46
+ * Navigate to view
47
+ */
48
+ navigateTo(viewId: scalar.ViewId, fromNode?: scalar.NodeId): void
49
+ /**
50
+ * Navigate back or forward in history
51
+ */
52
+ navigate(direction: 'back' | 'forward'): void
53
+ /**
54
+ * Fit diagram to view
55
+ */
56
+ fitDiagram(duration?: number): void
57
+ /**
58
+ * Open relationships browser
59
+ */
60
+ openRelationshipsBrowser(fqn: scalar.Fqn): void
61
+ /**
62
+ * If running in editor, trigger opening source file
63
+ */
64
+ openSource(params: OpenSourceParams<aux.Unknown>): void
65
+ /**
66
+ * Open element details card
67
+ */
68
+ openElementDetails(fqn: scalar.Fqn, fromNode?: scalar.NodeId): void
69
+ openRelationshipDetails(...params: [edgeId: scalar.EdgeId] | [source: scalar.Fqn, target: scalar.Fqn]): void
70
+ updateNodeData(nodeId: scalar.NodeId, data: PartialDeep<Types.NodeData>): void
71
+ updateEdgeData(edgeId: scalar.EdgeId, data: PartialDeep<Types.EdgeData>): void
72
+ /**
73
+ * Schedule save manual layout
74
+ */
75
+ scheduleSaveManualLayout(): void
76
+ /**
77
+ * @returns true if there was pending request to save layout
78
+ */
79
+ cancelSaveManualLayout(): boolean
80
+ /**
81
+ * Align nodes
82
+ */
83
+ align(mode: AlignmentMode): void
84
+ /**
85
+ * Reset edge control points
86
+ */
87
+ resetEdgeControlPoints(): void
88
+ /**
89
+ * Focus node
90
+ */
91
+ focusNode(nodeId: NodeId): void
92
+
93
+ /**
94
+ * @warning Do not use in render phase
95
+ */
96
+ getSnapshot(): DiagramActorSnapshot
97
+ /**
98
+ * @warning Do not use in render phase
99
+ */
100
+ getContext(): DiagramContext
101
+ /**
102
+ * @warning Do not use in render phase
103
+ */
104
+ findDiagramNode(xynodeId: string): DiagramNode | null
105
+ /**
106
+ * @warning Do not use in render phase
107
+ */
108
+ findDiagramEdge(xyedgeId: string): DiagramEdge | null
109
+ startWalkthrough(): void
110
+ walkthroughStep(direction?: 'next' | 'previous'): void
111
+ stopWalkthrough(): void
112
+ toggleFeature(feature: FeatureName, forceValue?: boolean): void
113
+ highlightNotation(notation: ElementNotation, kind?: string): void
114
+ unhighlightNotation(): void
115
+ openSearch(searchValue?: string): void
116
+ }
117
+
32
118
  /**
33
119
  * Diagram API
34
120
  * Mostly for internal use
35
121
  */
36
- export function useDiagram() {
122
+ export function useDiagram(): DiagramApi {
37
123
  const actor = useDiagramActorRef()
38
- return useMemo(() => ({
124
+ return useMemo((): DiagramApi => ({
39
125
  actor,
40
126
  send: (event: DiagramActorEvent) => actor.send(event),
41
127
  navigateTo: (viewId: ViewId, fromNode?: NodeId) => {
@@ -51,16 +137,16 @@ export function useDiagram() {
51
137
  fitDiagram: (duration = 350) => {
52
138
  actor.send({ type: 'fitDiagram', duration })
53
139
  },
54
- openRelationshipsBrowser: (fqn: Fqn) => {
140
+ openRelationshipsBrowser: (fqn) => {
55
141
  actor.send({ type: 'open.relationshipsBrowser', fqn })
56
142
  },
57
- openSource: (params: OpenSourceParams) => {
143
+ openSource: (params: OpenSourceParams<aux.Unknown>) => {
58
144
  actor.send({ type: 'open.source', ...params })
59
145
  },
60
- openElementDetails: (fqn: Fqn, fromNode?: NodeId) => {
146
+ openElementDetails: (fqn, fromNode?: scalar.NodeId) => {
61
147
  actor.send({ type: 'open.elementDetails', fqn, fromNode })
62
148
  },
63
- openRelationshipDetails: (...params: [edgeId: EdgeId] | [source: Fqn, target: Fqn]) => {
149
+ openRelationshipDetails: (...params: [edgeId: scalar.EdgeId] | [source: scalar.Fqn, target: scalar.Fqn]) => {
64
150
  if (params.length === 1) {
65
151
  actor.send({ type: 'open.relationshipDetails', params: { edgeId: params[0] } })
66
152
  } else {
@@ -68,10 +154,10 @@ export function useDiagram() {
68
154
  }
69
155
  },
70
156
 
71
- updateNodeData: (nodeId: NodeId, data: PartialDeep<Types.NodeData>) => {
157
+ updateNodeData: (nodeId: scalar.NodeId, data: PartialDeep<Types.NodeData>) => {
72
158
  actor.send({ type: 'update.nodeData', nodeId, data })
73
159
  },
74
- updateEdgeData: (edgeId: EdgeId, data: PartialDeep<Types.EdgeData>) => {
160
+ updateEdgeData: (edgeId: scalar.EdgeId, data: PartialDeep<Types.EdgeData>) => {
75
161
  actor.send({
76
162
  type: 'update.edgeData',
77
163
  edgeId,
@@ -151,6 +237,10 @@ export function useDiagram() {
151
237
  unhighlightNotation: () => {
152
238
  actor.send({ type: 'notations.unhighlight' })
153
239
  },
240
+
241
+ openSearch: (searchValue?: string) => {
242
+ actor.send({ type: 'open.search', ...(searchValue && { search: searchValue }) })
243
+ },
154
244
  }), [actor])
155
245
  }
156
246
 
@@ -176,7 +266,9 @@ export function useDiagramSyncLayoutState<T = unknown>(
176
266
  export function useDiagramContext<T = unknown>(
177
267
  selector: (context: DiagramContext) => T,
178
268
  compare: (a: NoInfer<T>, b: NoInfer<T>) => boolean = shallowEqual,
269
+ deps?: DependencyList,
179
270
  ): T {
180
271
  const actorRef = useDiagramActorRef()
181
- return useXstateSelector(actorRef, useCallbackRef(s => selector(s.context)), compare)
272
+ const select = useCallback((s: DiagramActorSnapshot) => selector(s.context), deps ?? [])
273
+ return useXstateSelector(actorRef, select, compare)
182
274
  }
@@ -2,7 +2,16 @@ import { useMemo } from 'react'
2
2
 
3
3
  import { useRootContainer } from '../context'
4
4
 
5
- export function useMantinePortalProps() {
5
+ export function useMantinePortalProps():
6
+ | {
7
+ portalProps: { target: HTMLDivElement }
8
+ withinPortal: true
9
+ }
10
+ | {
11
+ withinPortal: false
12
+ portalProps?: never
13
+ }
14
+ {
6
15
  const target = useRootContainer()
7
16
  return useMemo(() => target ? { portalProps: { target }, withinPortal: true } : { withinPortal: false }, [target])
8
17
  }
@@ -0,0 +1,11 @@
1
+ import type { SearchActorRef } from '../search/searchActor'
2
+ import type { DiagramActorSnapshot } from '../state/types'
3
+ import { useDiagramActorSnapshot } from './useDiagram'
4
+
5
+ const select = (s: DiagramActorSnapshot) => {
6
+ return s.children.search ?? null
7
+ }
8
+
9
+ export function useSearchActorRef(): SearchActorRef | null {
10
+ return useDiagramActorSnapshot(select, Object.is)
11
+ }
@@ -2,7 +2,7 @@ import {
2
2
  type DependenciesComparator,
3
3
  type EffectHook,
4
4
  useCustomCompareEffect,
5
- useFirstMountState
5
+ useFirstMountState,
6
6
  } from '@react-hookz/web'
7
7
  import { shallowEqual } from 'fast-equals'
8
8
  import { type DependencyList, type EffectCallback } from 'react'
@@ -17,6 +17,9 @@ export const depsShallowEqual: DependenciesComparator = (d1, d2) => {
17
17
  return false
18
18
  }
19
19
  for (const [i, element] of d1.entries()) {
20
+ if (element === d2[i]) {
21
+ continue
22
+ }
20
23
  if (!shallowEqual(element, d2[i])) {
21
24
  return false
22
25
  }
@@ -26,18 +29,18 @@ export const depsShallowEqual: DependenciesComparator = (d1, d2) => {
26
29
 
27
30
  export function useUpdateEffect<
28
31
  Callback extends EffectCallback = EffectCallback,
29
- Deps extends DependencyList = DependencyList
32
+ Deps extends DependencyList = DependencyList,
30
33
  >(
31
34
  callback: Callback,
32
35
  deps: Deps,
33
36
  equalityFn?: DependenciesComparator<Deps>,
34
- effectHook?: EffectHook<Callback, Deps>
37
+ effectHook?: EffectHook<Callback, Deps>,
35
38
  ) {
36
39
  const isFirstMount = useFirstMountState()
37
40
  useCustomCompareEffect(
38
41
  isFirstMount ? noop as Callback : callback,
39
42
  deps,
40
43
  equalityFn ?? depsShallowEqual,
41
- effectHook
44
+ effectHook,
42
45
  )
43
46
  }
@@ -20,6 +20,11 @@ export type XYStoreApi = ReturnType<typeof useXYStoreApi>
20
20
 
21
21
  export const useXYInternalNode = useInternalNode<Types.Node>
22
22
 
23
+ const selectCurrentZoom = (state: ReactFlowState) => Math.round(state.transform[2] * 100) / 100
24
+ export function useCurrentZoom(): number {
25
+ return useStore(selectCurrentZoom)
26
+ }
27
+
23
28
  const selectZoom = (state: ReactFlowState) => state.transform[2] < 0.2
24
29
  export function useIsZoomTooSmall(): boolean {
25
30
  return useStore(selectZoom)
@@ -1,7 +1,9 @@
1
1
  import { memo } from 'react'
2
2
  import { useEnabledFeatures } from '../context'
3
3
  import { useOverlaysActorRef } from '../hooks/useOverlaysActor'
4
+ import { useSearchActorRef } from '../hooks/useSearchActor'
4
5
  import { Overlays } from '../overlays/Overlays'
6
+ import { Search } from '../search/Search'
5
7
  import { Controls, DiagramTitlePanel, DynamicViewWalkthrough, NotationPanel } from './ui'
6
8
 
7
9
  export const DiagramUI = memo(() => {
@@ -9,9 +11,11 @@ export const DiagramUI = memo(() => {
9
11
  enableViewTitle,
10
12
  enableNotations,
11
13
  enableDynamicViewWalkthrough,
14
+ enableSearch,
12
15
  } = useEnabledFeatures()
13
16
 
14
17
  const overlaysActorRef = useOverlaysActorRef()
18
+ const searchActorRef = useSearchActorRef()
15
19
 
16
20
  return (
17
21
  <>
@@ -20,6 +24,7 @@ export const DiagramUI = memo(() => {
20
24
  {enableViewTitle && <DiagramTitlePanel />}
21
25
  {enableNotations && <NotationPanel />}
22
26
  {enableDynamicViewWalkthrough && <DynamicViewWalkthrough />}
27
+ {enableSearch && searchActorRef && <Search searchActorRef={searchActorRef} />}
23
28
  </>
24
29
  )
25
30
  })
@@ -3,8 +3,9 @@ import { cx } from '@likec4/styles/css'
3
3
  import { useCallbackRef, useDebouncedCallback, useTimeout } from '@mantine/hooks'
4
4
  import { useCustomCompareMemo } from '@react-hookz/web'
5
5
  import type { OnMove, OnMoveEnd } from '@xyflow/system'
6
- import { deepEqual, shallowEqual } from 'fast-equals'
7
- import { type PropsWithChildren, memo } from 'react'
6
+ import { shallowEqual } from 'fast-equals'
7
+ import { type PropsWithChildren } from 'react'
8
+ import type { Simplify } from 'type-fest'
8
9
  import { BaseXYFlow } from '../base/BaseXYFlow'
9
10
  import { useDiagramEventHandlers } from '../context'
10
11
  import { useIsReducedGraphics, usePanningAtom } from '../context/ReduceGraphics'
@@ -46,32 +47,25 @@ const equalsXYProps = (a: ReturnType<typeof selectXYProps>, b: ReturnType<typeof
46
47
  shallowEqual(a.viewport ?? null, b.viewport ?? null)
47
48
 
48
49
  export type LikeC4DiagramXYFlowProps = PropsWithChildren<
49
- Pick<
50
- LikeC4DiagramProperties,
51
- | 'background'
52
- | 'nodesDraggable'
53
- | 'nodesSelectable'
54
- | 'reactFlowProps'
55
- | 'renderNodes'
50
+ Simplify<
51
+ Pick<
52
+ LikeC4DiagramProperties<any>,
53
+ | 'background'
54
+ | 'nodesDraggable'
55
+ | 'nodesSelectable'
56
+ | 'reactFlowProps'
57
+ | 'renderNodes'
58
+ >
56
59
  >
57
60
  >
58
-
59
- const compareProps = <T extends LikeC4DiagramXYFlowProps>(a: T, b: T): boolean =>
60
- a.nodesDraggable == b.nodesDraggable &&
61
- a.nodesSelectable == b.nodesSelectable &&
62
- a.children == b.children &&
63
- deepEqual(a.background, b.background) &&
64
- deepEqual(a.reactFlowProps ?? {}, b.reactFlowProps ?? {}) &&
65
- shallowEqual(a.renderNodes ?? {}, b.renderNodes ?? {})
66
-
67
- export const LikeC4DiagramXYFlow = memo<LikeC4DiagramXYFlowProps>(({
61
+ export function LikeC4DiagramXYFlow({
68
62
  background = 'dots',
69
63
  nodesDraggable = false,
70
64
  nodesSelectable = false,
71
65
  reactFlowProps = {},
72
66
  children,
73
67
  renderNodes,
74
- }) => {
68
+ }: LikeC4DiagramXYFlowProps) {
75
69
  const diagram = useDiagram()
76
70
  const {
77
71
  initialized,
@@ -131,7 +125,9 @@ export const LikeC4DiagramXYFlow = memo<LikeC4DiagramXYFlowProps>(({
131
125
  'compound-element': renderNodes?.compoundElement ?? defaultNodeTypes['compound-element'],
132
126
  'compound-deployment': renderNodes?.compoundDeployment ?? defaultNodeTypes['compound-deployment'],
133
127
  'view-group': renderNodes?.viewGroup ?? defaultNodeTypes['view-group'],
134
- } satisfies { [key in Types.Node['type']]: any }
128
+ } satisfies {
129
+ [key in Types.Node['type']]: any
130
+ }
135
131
  },
136
132
  [renderNodes],
137
133
  shallowEqual,
@@ -139,104 +135,105 @@ export const LikeC4DiagramXYFlow = memo<LikeC4DiagramXYFlowProps>(({
139
135
 
140
136
  useUpdateEffect(() => {
141
137
  console.warn('renderNodes changed - this might degrade performance')
142
- }, [renderNodes])
138
+ }, [nodeTypes])
143
139
 
144
140
  return (
145
- <BaseXYFlow<Types.Node, Types.Edge>
146
- nodes={nodes}
147
- edges={edges}
148
- className={cx(initialized ? 'initialized' : 'not-initialized')}
149
- nodeTypes={nodeTypes}
150
- edgeTypes={edgeTypes}
151
- onNodesChange={useCallbackRef((changes) => {
152
- diagram.send({ type: 'xyflow.applyNodeChanges', changes })
153
- })}
154
- onEdgesChange={useCallbackRef((changes) => {
155
- diagram.send({ type: 'xyflow.applyEdgeChanges', changes })
156
- })}
157
- background={initialized ? background : 'transparent'}
158
- // Fitview is handled in onInit
159
- fitView={false}
160
- onNodeClick={useCallbackRef((e, node) => {
161
- e.stopPropagation()
162
- diagram.send({ type: 'xyflow.nodeClick', node })
163
- onNodeClick?.(diagram.findDiagramNode(node.id as NodeId)!, e)
164
- })}
165
- onEdgeClick={useCallbackRef((e, edge) => {
166
- e.stopPropagation()
167
- diagram.send({ type: 'xyflow.edgeClick', edge })
168
- onEdgeClick?.(diagram.findDiagramEdge(edge.id as EdgeId)!, e)
169
- })}
170
- onPaneClick={useCallbackRef((e) => {
171
- e.stopPropagation()
172
- diagram.send({ type: 'xyflow.paneClick' })
173
- onCanvasClick?.(e as any)
174
- })}
175
- onDoubleClick={useCallbackRef(e => {
176
- e.stopPropagation()
177
- e.preventDefault()
178
- diagram.send({ type: 'xyflow.paneDblClick' })
179
- onCanvasDblClick?.(e as any)
180
- })}
181
- onNodeMouseEnter={useCallbackRef((_event, node) => {
182
- _event.stopPropagation()
183
- if (!node.data.hovered) {
184
- diagram.send({ type: 'xyflow.nodeMouseEnter', node })
185
- }
186
- })}
187
- onNodeMouseLeave={useCallbackRef((_event, node) => {
188
- _event.stopPropagation()
189
- if (node.data.hovered) {
190
- diagram.send({ type: 'xyflow.nodeMouseLeave', node })
191
- }
192
- })}
193
- onEdgeMouseEnter={useCallbackRef((_event, edge) => {
194
- _event.stopPropagation()
195
- if (!edge.data.hovered) {
196
- diagram.send({ type: 'xyflow.edgeMouseEnter', edge })
197
- }
198
- })}
199
- onEdgeMouseLeave={useCallbackRef((_event, edge) => {
200
- _event.stopPropagation()
201
- if (edge.data.hovered) {
202
- diagram.send({ type: 'xyflow.edgeMouseLeave', edge })
203
- }
204
- })}
205
- {...props.pannable && {
206
- onMove,
207
- }}
208
- onMoveEnd={onMoveEnd}
209
- onInit={useCallbackRef((instance) => {
210
- diagram.send({ type: 'xyflow.init', instance })
211
- })}
212
- onNodeContextMenu={useCallbackRef((event, node) => {
213
- const diagramNode = nonNullable(
214
- diagram.findDiagramNode(node.id as NodeId),
215
- `diagramNode ${node.id} not found`,
216
- )
217
- onNodeContextMenu?.(diagramNode, event)
218
- })}
219
- onEdgeContextMenu={useCallbackRef((event, edge) => {
220
- const diagramEdge = nonNullable(
221
- diagram.findDiagramEdge(edge.id as EdgeId),
222
- `diagramEdge ${edge.id} not found`,
223
- )
224
- onEdgeContextMenu?.(diagramEdge, event)
225
- })}
226
- onPaneContextMenu={useCallbackRef((event) => {
227
- onCanvasContextMenu?.(event as any)
228
- })}
229
- {...enableFitView && {
230
- onViewportResize,
231
- }}
232
- nodesDraggable={notReadOnly && nodesDraggable}
233
- nodesSelectable={nodesSelectable}
234
- {...(notReadOnly && nodesDraggable && layoutConstraints)}
235
- {...props}
236
- {...reactFlowProps}>
141
+ <>
142
+ <BaseXYFlow<Types.Node, Types.Edge>
143
+ nodes={nodes}
144
+ edges={edges}
145
+ className={cx(initialized ? 'initialized' : 'not-initialized')}
146
+ nodeTypes={nodeTypes}
147
+ edgeTypes={edgeTypes}
148
+ onNodesChange={useCallbackRef((changes) => {
149
+ diagram.send({ type: 'xyflow.applyNodeChanges', changes })
150
+ })}
151
+ onEdgesChange={useCallbackRef((changes) => {
152
+ diagram.send({ type: 'xyflow.applyEdgeChanges', changes })
153
+ })}
154
+ background={initialized ? background : 'transparent'}
155
+ // Fitview is handled in onInit
156
+ fitView={false}
157
+ onNodeClick={useCallbackRef((e, node) => {
158
+ e.stopPropagation()
159
+ diagram.send({ type: 'xyflow.nodeClick', node })
160
+ onNodeClick?.(diagram.findDiagramNode(node.id as NodeId)!, e)
161
+ })}
162
+ onEdgeClick={useCallbackRef((e, edge) => {
163
+ e.stopPropagation()
164
+ diagram.send({ type: 'xyflow.edgeClick', edge })
165
+ onEdgeClick?.(diagram.findDiagramEdge(edge.id as EdgeId)!, e)
166
+ })}
167
+ onPaneClick={useCallbackRef((e) => {
168
+ e.stopPropagation()
169
+ diagram.send({ type: 'xyflow.paneClick' })
170
+ onCanvasClick?.(e as any)
171
+ })}
172
+ onDoubleClick={useCallbackRef(e => {
173
+ e.stopPropagation()
174
+ e.preventDefault()
175
+ diagram.send({ type: 'xyflow.paneDblClick' })
176
+ onCanvasDblClick?.(e as any)
177
+ })}
178
+ onNodeMouseEnter={useCallbackRef((_event, node) => {
179
+ _event.stopPropagation()
180
+ if (!node.data.hovered) {
181
+ diagram.send({ type: 'xyflow.nodeMouseEnter', node })
182
+ }
183
+ })}
184
+ onNodeMouseLeave={useCallbackRef((_event, node) => {
185
+ _event.stopPropagation()
186
+ if (node.data.hovered) {
187
+ diagram.send({ type: 'xyflow.nodeMouseLeave', node })
188
+ }
189
+ })}
190
+ onEdgeMouseEnter={useCallbackRef((_event, edge) => {
191
+ _event.stopPropagation()
192
+ if (!edge.data.hovered) {
193
+ diagram.send({ type: 'xyflow.edgeMouseEnter', edge })
194
+ }
195
+ })}
196
+ onEdgeMouseLeave={useCallbackRef((_event, edge) => {
197
+ _event.stopPropagation()
198
+ if (edge.data.hovered) {
199
+ diagram.send({ type: 'xyflow.edgeMouseLeave', edge })
200
+ }
201
+ })}
202
+ {...props.pannable && {
203
+ onMove,
204
+ }}
205
+ onMoveEnd={onMoveEnd}
206
+ onInit={useCallbackRef((instance) => {
207
+ diagram.send({ type: 'xyflow.init', instance })
208
+ })}
209
+ onNodeContextMenu={useCallbackRef((event, node) => {
210
+ const diagramNode = nonNullable(
211
+ diagram.findDiagramNode(node.id as NodeId),
212
+ `diagramNode ${node.id} not found`,
213
+ )
214
+ onNodeContextMenu?.(diagramNode, event)
215
+ })}
216
+ onEdgeContextMenu={useCallbackRef((event, edge) => {
217
+ const diagramEdge = nonNullable(
218
+ diagram.findDiagramEdge(edge.id as EdgeId),
219
+ `diagramEdge ${edge.id} not found`,
220
+ )
221
+ onEdgeContextMenu?.(diagramEdge, event)
222
+ })}
223
+ onPaneContextMenu={useCallbackRef((event) => {
224
+ onCanvasContextMenu?.(event as any)
225
+ })}
226
+ {...enableFitView && {
227
+ onViewportResize,
228
+ }}
229
+ nodesDraggable={notReadOnly && nodesDraggable}
230
+ nodesSelectable={nodesSelectable}
231
+ {...(notReadOnly && nodesDraggable && layoutConstraints)}
232
+ {...props}
233
+ {...reactFlowProps}>
234
+ {children}
235
+ </BaseXYFlow>
237
236
  <DiagramUI key={'DiagramUI'} />
238
- {children}
239
- </BaseXYFlow>
237
+ </>
240
238
  )
241
- }, compareProps)
242
- LikeC4DiagramXYFlow.displayName = 'LikeC4DiagramXYFlow'
239
+ }
@@ -193,6 +193,10 @@ export const RelationshipEdge = customEdge<Types.RelationshipEdgeData>((props) =
193
193
  }
194
194
  setIsControlPointDragging(false)
195
195
  }
196
+ const onClick = (e: MouseEvent) => {
197
+ e.stopPropagation()
198
+ e.preventDefault()
199
+ }
196
200
 
197
201
  domNode.addEventListener('pointermove', onPointerMove, {
198
202
  capture: true,
@@ -201,6 +205,11 @@ export const RelationshipEdge = customEdge<Types.RelationshipEdgeData>((props) =
201
205
  once: true,
202
206
  capture: true,
203
207
  })
208
+ // Handle click to prevent it from being handled by the edge #1945
209
+ domNode.addEventListener('click', onClick, {
210
+ capture: true,
211
+ once: true,
212
+ })
204
213
  }
205
214
 
206
215
  const onRmbControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>, domNode: HTMLDivElement) => {
@@ -1,11 +1,10 @@
1
1
  import {
2
2
  type DiagramEdge,
3
+ type DiagramNode,
3
4
  type EdgeId,
4
- type LikeC4Model,
5
- type NodeId,
6
- DiagramNode,
7
5
  nameFromFqn,
8
6
  } from '@likec4/core'
7
+ import type { LikeC4Model } from '@likec4/core/model'
9
8
  import { css, cx } from '@likec4/styles/css'
10
9
  import {
11
10
  type StackProps,
@@ -63,13 +62,15 @@ export const RelationshipsDropdownMenu = memo((
63
62
  }>,
64
63
  ) => {
65
64
  const { diagramEdge, sourceNode, targetNode } = useDiagramContext(
66
- useCallback(ctx => ({
65
+ ctx => ({
67
66
  diagramEdge: findDiagramEdge(ctx, edgeId),
68
67
  sourceNode: findDiagramNode(ctx, source),
69
68
  targetNode: findDiagramNode(ctx, target),
70
- }), [edgeId, source, target]),
69
+ }),
70
+ undefined,
71
+ [edgeId, source, target],
71
72
  )
72
- const likec4model = useLikeC4Model(true)
73
+ const likec4model = useLikeC4Model()
73
74
  const diagram = useDiagram()
74
75
 
75
76
  const portalProps = useMantinePortalProps()
@@ -266,15 +267,15 @@ const Relationship = forwardRef<
266
267
  })
267
268
 
268
269
  function getShortId(
269
- r: LikeC4Model.AnyRelation<LikeC4Model.Any>,
270
- actualEndpointId: NodeId<string>,
270
+ r: LikeC4Model.AnyRelation,
271
+ actualEndpointId: string,
271
272
  diagramNode: DiagramNode,
272
273
  ) {
273
274
  const diagramNodeId = r.isDeploymentRelation()
274
275
  // Relation defined in deployment model. Use id of the deployment node as is.
275
276
  ? diagramNode.id
276
277
  // Relation defined in model. Get id of the model element
277
- : DiagramNode.modelRef(diagramNode) || ''
278
+ : diagramNode.modelRef || ''
278
279
 
279
280
  return nameFromFqn(diagramNodeId) + actualEndpointId.slice(diagramNodeId.length)
280
281
  }