@likec4/diagram 1.18.0 → 1.19.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 (277) hide show
  1. package/LICENSE +1 -1
  2. package/dist/LikeC4CustomColors.d.ts +7 -0
  3. package/dist/LikeC4CustomColors.js +30 -0
  4. package/dist/LikeC4Diagram.css.d.ts +5 -0
  5. package/dist/LikeC4Diagram.css.js +13 -0
  6. package/dist/LikeC4Diagram.d.ts +6 -0
  7. package/dist/LikeC4Diagram.js +194 -0
  8. package/dist/LikeC4Diagram.props.d.ts +166 -0
  9. package/dist/LikeC4ModelProvider.d.ts +9 -0
  10. package/dist/LikeC4ModelProvider.js +12 -0
  11. package/dist/LikeC4Search.css.d.ts +1 -0
  12. package/dist/LikeC4Search.css.js +5 -0
  13. package/dist/LikeC4Search.d.ts +2 -0
  14. package/dist/LikeC4Search.js +96 -0
  15. package/dist/StaticLikeC4Diagram.d.ts +3 -0
  16. package/dist/StaticLikeC4Diagram.js +41 -0
  17. package/dist/_virtual/_commonjsHelpers.js +6 -0
  18. package/dist/controls/Text.d.ts +2 -0
  19. package/dist/controls/Text.js +7 -0
  20. package/dist/controls/action-button-bar/ActionButtonBar.css.d.ts +1 -0
  21. package/dist/controls/action-button-bar/ActionButtonBar.css.js +5 -0
  22. package/dist/controls/action-button-bar/ActionButtonBar.d.ts +9 -0
  23. package/dist/controls/action-button-bar/ActionButtonBar.js +100 -0
  24. package/dist/controls/action-button-bar/useActionButtonBarCtx.d.ts +10 -0
  25. package/dist/controls/action-button-bar/useActionButtonBarCtx.js +9 -0
  26. package/dist/controls/action-buttons/ActionButton.css.d.ts +1 -0
  27. package/dist/controls/action-buttons/ActionButton.css.js +5 -0
  28. package/dist/controls/action-buttons/ActionButton.d.ts +9 -0
  29. package/dist/controls/action-buttons/ActionButton.js +66 -0
  30. package/dist/controls/action-buttons/ActionButtons.d.ts +12 -0
  31. package/dist/controls/action-buttons/ActionButtons.js +99 -0
  32. package/dist/globals.css.d.ts +1 -0
  33. package/dist/globals.css.js +92 -0
  34. package/dist/hooks/index.d.ts +5 -0
  35. package/dist/hooks/useDiagramState.d.ts +6 -0
  36. package/dist/hooks/useDiagramState.js +27 -0
  37. package/dist/hooks/useMantinePortalProps.d.ts +9 -0
  38. package/dist/hooks/useMantinePortalProps.js +9 -0
  39. package/dist/hooks/useSetState.d.ts +2 -0
  40. package/dist/hooks/useSetState.js +19 -0
  41. package/dist/hooks/useUpdateEffect.d.ts +4 -0
  42. package/dist/hooks/useUpdateEffect.js +32 -0
  43. package/dist/hooks/useXYFlow.d.ts +270 -0
  44. package/dist/hooks/useXYFlow.js +20 -0
  45. package/dist/index.d.ts +11 -0
  46. package/dist/index.js +25 -0
  47. package/dist/likec4model/LikeC4ModelContext.d.ts +3 -0
  48. package/dist/likec4model/LikeC4ModelContext.js +5 -0
  49. package/dist/likec4model/index.d.ts +2 -0
  50. package/dist/likec4model/useLikeC4ElementsTree.d.ts +12 -0
  51. package/dist/likec4model/useLikeC4ElementsTree.js +25 -0
  52. package/dist/likec4model/useLikeC4Model.d.ts +20 -0
  53. package/dist/likec4model/useLikeC4Model.js +55 -0
  54. package/dist/overlays/OverlayContext.d.ts +10 -0
  55. package/dist/overlays/OverlayContext.js +9 -0
  56. package/dist/overlays/Overlays.css.d.ts +3 -0
  57. package/dist/overlays/Overlays.css.js +7 -0
  58. package/dist/overlays/Overlays.d.ts +2 -0
  59. package/dist/overlays/Overlays.js +137 -0
  60. package/dist/overlays/edge-details/EdgeDetailsXYFlow.d.ts +5 -0
  61. package/dist/overlays/edge-details/EdgeDetailsXYFlow.js +185 -0
  62. package/dist/overlays/edge-details/SelectEdge.css.d.ts +7 -0
  63. package/dist/overlays/edge-details/SelectEdge.css.js +17 -0
  64. package/dist/overlays/edge-details/SelectEdge.d.ts +5 -0
  65. package/dist/overlays/edge-details/SelectEdge.js +129 -0
  66. package/dist/overlays/edge-details/_types.d.ts +14 -0
  67. package/dist/overlays/edge-details/use-layouted-edge-details.d.ts +21 -0
  68. package/dist/overlays/edge-details/use-layouted-edge-details.js +270 -0
  69. package/dist/overlays/edge-details/xyflow/CompoundNode.d.ts +5 -0
  70. package/dist/overlays/edge-details/xyflow/CompoundNode.js +76 -0
  71. package/dist/overlays/edge-details/xyflow/ElementNode.d.ts +5 -0
  72. package/dist/overlays/edge-details/xyflow/ElementNode.js +159 -0
  73. package/dist/overlays/edge-details/xyflow/RelationshipEdge.d.ts +3 -0
  74. package/dist/overlays/edge-details/xyflow/RelationshipEdge.js +84 -0
  75. package/dist/overlays/edge-details/xyflow/styles.css.d.ts +9 -0
  76. package/dist/overlays/edge-details/xyflow/styles.css.js +21 -0
  77. package/dist/overlays/element-details/ElementDetailsCard.css.d.ts +16 -0
  78. package/dist/overlays/element-details/ElementDetailsCard.css.js +33 -0
  79. package/dist/overlays/element-details/ElementDetailsCard.d.ts +7 -0
  80. package/dist/overlays/element-details/ElementDetailsCard.js +484 -0
  81. package/dist/overlays/element-details/TabPanelDeployments.css.d.ts +4 -0
  82. package/dist/overlays/element-details/TabPanelDeployments.css.js +11 -0
  83. package/dist/overlays/element-details/TabPanelDeployments.d.ts +7 -0
  84. package/dist/overlays/element-details/TabPanelDeployments.js +173 -0
  85. package/dist/overlays/element-details/TabPanelRelationships.css.d.ts +5 -0
  86. package/dist/overlays/element-details/TabPanelRelationships.css.js +11 -0
  87. package/dist/overlays/element-details/TabPanelRelationships.d.ts +8 -0
  88. package/dist/overlays/element-details/TabPanelRelationships.js +157 -0
  89. package/dist/overlays/element-details/TabPanelStructure.css.d.ts +2 -0
  90. package/dist/overlays/element-details/TabPanelStructure.css.js +7 -0
  91. package/dist/overlays/element-details/TabPanelStructure.d.ts +25 -0
  92. package/dist/overlays/element-details/TabPanelStructure.js +91 -0
  93. package/dist/overlays/index.d.ts +1 -0
  94. package/dist/overlays/relationships-of/RelationshipsOverlay.d.ts +5 -0
  95. package/dist/overlays/relationships-of/RelationshipsOverlay.js +193 -0
  96. package/dist/overlays/relationships-of/RelationshipsXYFlow.d.ts +19 -0
  97. package/dist/overlays/relationships-of/RelationshipsXYFlow.js +290 -0
  98. package/dist/overlays/relationships-of/SelectElement.css.d.ts +2 -0
  99. package/dist/overlays/relationships-of/SelectElement.css.js +7 -0
  100. package/dist/overlays/relationships-of/SelectElement.d.ts +7 -0
  101. package/dist/overlays/relationships-of/SelectElement.js +126 -0
  102. package/dist/overlays/relationships-of/_types.d.ts +28 -0
  103. package/dist/overlays/relationships-of/use-layouted-relationships.d.ts +22 -0
  104. package/dist/overlays/relationships-of/use-layouted-relationships.js +496 -0
  105. package/dist/overlays/relationships-of/xyflow/CompoundNode.d.ts +6 -0
  106. package/dist/overlays/relationships-of/xyflow/CompoundNode.js +120 -0
  107. package/dist/overlays/relationships-of/xyflow/ElementNode.d.ts +6 -0
  108. package/dist/overlays/relationships-of/xyflow/ElementNode.js +194 -0
  109. package/dist/overlays/relationships-of/xyflow/EmptyNode.d.ts +5 -0
  110. package/dist/overlays/relationships-of/xyflow/EmptyNode.js +18 -0
  111. package/dist/overlays/relationships-of/xyflow/RelationshipEdge.d.ts +3 -0
  112. package/dist/overlays/relationships-of/xyflow/RelationshipEdge.js +123 -0
  113. package/dist/overlays/relationships-of/xyflow/styles.css.d.ts +14 -0
  114. package/dist/overlays/relationships-of/xyflow/styles.css.js +24 -0
  115. package/dist/overlays/shared/xyflow/RelationshipEdge.css.d.ts +4 -0
  116. package/dist/overlays/shared/xyflow/RelationshipEdge.css.js +12 -0
  117. package/dist/overlays/shared/xyflow/_types.d.ts +77 -0
  118. package/dist/state/DiagramContext.d.ts +1609 -0
  119. package/dist/state/DiagramContext.js +101 -0
  120. package/dist/state/aligners.d.ts +42 -0
  121. package/dist/state/aligners.js +349 -0
  122. package/dist/state/diagram-to-xyflow.d.ts +11 -0
  123. package/dist/state/diagram-to-xyflow.js +113 -0
  124. package/dist/state/diagramStore.d.ts +1705 -0
  125. package/dist/state/diagramStore.js +808 -0
  126. package/dist/state/diagramStore.layout.d.ts +4 -0
  127. package/dist/state/diagramStore.layout.js +56 -0
  128. package/dist/style.css +1 -0
  129. package/dist/theme-vars.css.d.ts +72 -0
  130. package/dist/theme-vars.css.js +6 -0
  131. package/dist/theme-vars.css.ts.vanilla.css.js +1 -0
  132. package/dist/theme-vars.d.ts +3 -0
  133. package/dist/theme-vars.js +5 -0
  134. package/dist/ui/DiagramTitlePanel.css.d.ts +4 -0
  135. package/dist/ui/DiagramTitlePanel.css.js +11 -0
  136. package/dist/ui/DiagramTitlePanel.d.ts +1 -0
  137. package/dist/ui/DiagramTitlePanel.js +159 -0
  138. package/dist/ui/DynamicViewWalkthrough.css.d.ts +4 -0
  139. package/dist/ui/DynamicViewWalkthrough.css.js +11 -0
  140. package/dist/ui/DynamicViewWalkthrough.d.ts +1 -0
  141. package/dist/ui/DynamicViewWalkthrough.js +156 -0
  142. package/dist/ui/EnsureMantine.d.ts +7 -0
  143. package/dist/ui/EnsureMantine.js +14 -0
  144. package/dist/ui/FramerMotionConfig.d.ts +2 -0
  145. package/dist/ui/FramerMotionConfig.js +14 -0
  146. package/dist/ui/Link.d.ts +4 -0
  147. package/dist/ui/Link.js +36 -0
  148. package/dist/ui/notation/NotationPanel.css.d.ts +6 -0
  149. package/dist/ui/notation/NotationPanel.css.js +16 -0
  150. package/dist/ui/notation/NotationPanel.d.ts +1 -0
  151. package/dist/ui/notation/NotationPanel.js +250 -0
  152. package/dist/ui/notation/index.d.ts +1 -0
  153. package/dist/ui/top-left/ChangeAutoLayoutButton.d.ts +2 -0
  154. package/dist/ui/top-left/ChangeAutoLayoutButton.js +159 -0
  155. package/dist/ui/top-left/ManualLayoutToolsButton.d.ts +2 -0
  156. package/dist/ui/top-left/ManualLayoutToolsButton.js +137 -0
  157. package/dist/ui/top-left/TopLeftPanel.d.ts +4 -0
  158. package/dist/ui/top-left/TopLeftPanel.js +211 -0
  159. package/dist/ui/top-left/_shared.d.ts +7 -0
  160. package/dist/ui/top-left/_shared.js +22 -0
  161. package/dist/ui/top-left/styles.css.d.ts +8 -0
  162. package/dist/ui/top-left/styles.css.js +17 -0
  163. package/dist/utils/types.d.ts +8 -0
  164. package/dist/utils/vector.d.ts +24 -0
  165. package/dist/utils/vector.js +55 -0
  166. package/dist/xyflow/EdgeMarkers.d.ts +12 -0
  167. package/dist/xyflow/EdgeMarkers.js +192 -0
  168. package/dist/xyflow/FitviewOnDiagramChange.d.ts +4 -0
  169. package/dist/xyflow/FitviewOnDiagramChange.js +72 -0
  170. package/dist/xyflow/SelectEdgesOnNodeFocus.d.ts +1 -0
  171. package/dist/xyflow/SelectEdgesOnNodeFocus.js +96 -0
  172. package/dist/xyflow/XYFlow.d.ts +8 -0
  173. package/dist/xyflow/XYFlow.js +145 -0
  174. package/dist/xyflow/XYFlowBackground.d.ts +10 -0
  175. package/dist/xyflow/XYFlowBackground.js +25 -0
  176. package/dist/xyflow/XYFlowInner.d.ts +8 -0
  177. package/dist/xyflow/XYFlowInner.js +41 -0
  178. package/dist/xyflow/const.d.ts +7 -0
  179. package/dist/xyflow/const.js +12 -0
  180. package/dist/xyflow/edges/EdgeLabel.d.ts +7 -0
  181. package/dist/xyflow/edges/EdgeLabel.js +160 -0
  182. package/dist/xyflow/edges/RelationshipEdge.d.ts +6 -0
  183. package/dist/xyflow/edges/RelationshipEdge.js +443 -0
  184. package/dist/xyflow/edges/RelationshipsDropdownMenu.css.d.ts +4 -0
  185. package/dist/xyflow/edges/RelationshipsDropdownMenu.css.js +11 -0
  186. package/dist/xyflow/edges/RelationshipsDropdownMenu.d.ts +13 -0
  187. package/dist/xyflow/edges/RelationshipsDropdownMenu.js +211 -0
  188. package/dist/xyflow/edges/edges.css.d.ts +17 -0
  189. package/dist/xyflow/edges/edges.css.js +37 -0
  190. package/dist/xyflow/edges/utils.d.ts +16 -0
  191. package/dist/xyflow/edges/utils.js +24 -0
  192. package/dist/xyflow/nodes/AnimateVariants.d.ts +1313 -0
  193. package/dist/xyflow/nodes/AnimateVariants.js +123 -0
  194. package/dist/xyflow/nodes/Node.css.d.ts +3 -0
  195. package/dist/xyflow/nodes/Node.css.js +9 -0
  196. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +14 -0
  197. package/dist/xyflow/nodes/compound/CompoundNode.css.js +27 -0
  198. package/dist/xyflow/nodes/compound/CompoundNode.d.ts +6 -0
  199. package/dist/xyflow/nodes/compound/CompoundNode.js +216 -0
  200. package/dist/xyflow/nodes/compound/index.d.ts +1 -0
  201. package/dist/xyflow/nodes/element/ElementLink.css.d.ts +3 -0
  202. package/dist/xyflow/nodes/element/ElementLink.d.ts +6 -0
  203. package/dist/xyflow/nodes/element/ElementNode.d.ts +6 -0
  204. package/dist/xyflow/nodes/element/ElementNode.js +190 -0
  205. package/dist/xyflow/nodes/element/ElementShapeSvg.d.ts +17 -0
  206. package/dist/xyflow/nodes/element/ElementShapeSvg.js +175 -0
  207. package/dist/xyflow/nodes/element/element.css.d.ts +18 -0
  208. package/dist/xyflow/nodes/element/element.css.js +31 -0
  209. package/dist/xyflow/nodes/element/index.d.ts +1 -0
  210. package/dist/xyflow/nodes/shared/ElementIcon.d.ts +8 -0
  211. package/dist/xyflow/nodes/shared/ElementIcon.js +38 -0
  212. package/dist/xyflow/nodes/shared/Toolbar.d.ts +9 -0
  213. package/dist/xyflow/nodes/shared/Toolbar.js +436 -0
  214. package/dist/xyflow/types.d.ts +36 -0
  215. package/dist/xyflow/useLayoutConstraints.d.ts +42 -0
  216. package/dist/xyflow/useLayoutConstraints.js +226 -0
  217. package/dist/xyflow/useXYFlowEvents.d.ts +160 -0
  218. package/dist/xyflow/useXYFlowEvents.js +275 -0
  219. package/dist/xyflow/utils.d.ts +22 -0
  220. package/dist/xyflow/utils.js +72 -0
  221. package/package.json +34 -27
  222. package/src/LikeC4Diagram.tsx +4 -4
  223. package/src/LikeC4Search.css.ts +12 -0
  224. package/src/LikeC4Search.tsx +39 -90
  225. package/src/controls/Text.ts +5 -0
  226. package/src/controls/action-button-bar/ActionButtonBar.css.ts +13 -0
  227. package/src/controls/action-button-bar/ActionButtonBar.tsx +138 -0
  228. package/src/controls/action-button-bar/useActionButtonBarCtx.ts +13 -0
  229. package/src/controls/action-buttons/ActionButton.css.ts +29 -0
  230. package/src/controls/action-buttons/ActionButton.tsx +66 -0
  231. package/src/controls/action-buttons/ActionButtons.tsx +138 -0
  232. package/src/hooks/useXYFlow.ts +8 -8
  233. package/src/index.ts +12 -6
  234. package/src/likec4model/index.ts +12 -2
  235. package/src/overlays/edge-details/EdgeDetailsXYFlow.tsx +18 -12
  236. package/src/overlays/edge-details/_types.ts +13 -37
  237. package/src/overlays/edge-details/use-layouted-edge-details.ts +16 -14
  238. package/src/overlays/edge-details/xyflow/CompoundNode.tsx +3 -11
  239. package/src/overlays/edge-details/xyflow/ElementNode.tsx +4 -11
  240. package/src/overlays/edge-details/xyflow/RelationshipEdge.tsx +3 -3
  241. package/src/overlays/edge-details/xyflow/styles.css.ts +1 -59
  242. package/src/overlays/relationships-of/RelationshipsXYFlow.tsx +23 -23
  243. package/src/overlays/relationships-of/_types.ts +20 -58
  244. package/src/overlays/relationships-of/use-layouted-relationships.ts +36 -40
  245. package/src/overlays/relationships-of/xyflow/CompoundNode.tsx +9 -13
  246. package/src/overlays/relationships-of/xyflow/ElementNode.tsx +12 -15
  247. package/src/overlays/relationships-of/xyflow/EmptyNode.tsx +4 -7
  248. package/src/overlays/relationships-of/xyflow/RelationshipEdge.tsx +16 -14
  249. package/src/overlays/shared/xyflow/RelationshipEdge.css.ts +60 -0
  250. package/src/overlays/shared/xyflow/_types.ts +87 -0
  251. package/src/state/diagram-to-xyflow.ts +6 -7
  252. package/src/state/diagramStore.layout.ts +3 -4
  253. package/src/state/diagramStore.ts +35 -37
  254. package/src/theme-vars.css.ts +81 -0
  255. package/src/theme-vars.ts +8 -81
  256. package/src/ui/DiagramTitlePanel.tsx +6 -6
  257. package/src/utils/types.ts +6 -0
  258. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +3 -3
  259. package/src/xyflow/XYFlow.tsx +2 -2
  260. package/src/xyflow/edges/EdgeLabel.tsx +25 -18
  261. package/src/xyflow/edges/RelationshipEdge.tsx +5 -3
  262. package/src/xyflow/edges/RelationshipsDropdownMenu.tsx +3 -3
  263. package/src/xyflow/edges/edges.css.ts +68 -74
  264. package/src/xyflow/edges/utils.ts +6 -6
  265. package/src/xyflow/nodes/AnimateVariants.ts +143 -0
  266. package/src/xyflow/nodes/Node.css.ts +44 -0
  267. package/src/xyflow/nodes/compound/CompoundNode.css.ts +1 -64
  268. package/src/xyflow/nodes/compound/CompoundNode.tsx +69 -182
  269. package/src/xyflow/nodes/element/ElementLink.tsx +2 -3
  270. package/src/xyflow/nodes/element/ElementNode.tsx +64 -266
  271. package/src/xyflow/nodes/element/element.css.ts +0 -57
  272. package/src/xyflow/nodes/shared/Toolbar.tsx +30 -30
  273. package/src/xyflow/types.ts +48 -51
  274. package/src/xyflow/useLayoutConstraints.ts +9 -9
  275. package/src/xyflow/useXYFlowEvents.ts +13 -30
  276. package/src/xyflow/utils.ts +2 -2
  277. package/src/xyflow/nodes/use-animate-variants.tsx +0 -64
@@ -0,0 +1,143 @@
1
+ import { fallbackVar } from '@vanilla-extract/css'
2
+ import type { Variants } from 'framer-motion'
3
+ import { useMemo, useState } from 'react'
4
+ import { isEmpty, isNumber, isString } from 'remeda'
5
+ import { vars } from '../../theme-vars'
6
+
7
+ const DEFAULT_SCALE_BY = 0
8
+ const SELECTED_SCALE_BY = 16
9
+ const HOVERED_SCALE_BY = 12
10
+ const TAP_SCALE_BY = -16
11
+
12
+ const DELAY_NODE = 0.1
13
+ const DELAY_NODE_CHILDREN = 0.06
14
+
15
+ const DIMMED_OPACITY = 0.15
16
+ const DIMMED_DELAY = 0.2
17
+
18
+ export type VariantKeys = 'dimmed' | 'hoverd' | 'idle' | 'selected' | 'tap'
19
+
20
+ export const NodeVariants = (width: number, height: number, opts?: {
21
+ selectedScaleBy?: number
22
+ hoveredScaleBy?: number
23
+ tapScaleBy?: number
24
+ }) => {
25
+ const {
26
+ selectedScaleBy = SELECTED_SCALE_BY,
27
+ hoveredScaleBy = HOVERED_SCALE_BY,
28
+ tapScaleBy = TAP_SCALE_BY,
29
+ } = opts ?? {}
30
+
31
+ // Same scale for X and Y
32
+ const maxwh = Math.max(width, height)
33
+ const scaleBy = (diffPx: number) => ({
34
+ scale: (maxwh + diffPx) / maxwh,
35
+ // scaleY: (maxwh + diffPx) / maxwh,
36
+ })
37
+
38
+ return {
39
+ dimmed: {
40
+ filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(1px)')}`,
41
+ opacity: DIMMED_OPACITY,
42
+ transition: {
43
+ delay: DIMMED_DELAY,
44
+ ease: 'easeInOut',
45
+ },
46
+ willChange: 'opacity, filter',
47
+ },
48
+ idle: {
49
+ ...scaleBy(DEFAULT_SCALE_BY),
50
+ transition: {
51
+ delay: DELAY_NODE,
52
+ delayChildren: DELAY_NODE_CHILDREN,
53
+ },
54
+ filter: `grayscale(0) ${fallbackVar(vars.safariAnimationHook, 'blur(0px)')}`,
55
+ },
56
+ selected: {
57
+ ...scaleBy(selectedScaleBy),
58
+ },
59
+ hovered: (_, { scale }) => ({
60
+ ...scaleBy(hoveredScaleBy),
61
+ transition: !isNumber(scale) || (scale === 1)
62
+ ? ({
63
+ delay: DELAY_NODE,
64
+ delayChildren: DELAY_NODE_CHILDREN,
65
+ })
66
+ : {},
67
+ }),
68
+ tap: {
69
+ ...scaleBy(tapScaleBy),
70
+ },
71
+ } satisfies Variants
72
+ }
73
+
74
+ export function useFramerAnimateVariants() {
75
+ const [variants, setVariants] = useState<string[] | null>(null)
76
+
77
+ const handlers = useMemo(() => {
78
+ const getTarget = (e: MouseEvent | undefined) => {
79
+ try {
80
+ // 🤔 Sometimes target is null
81
+ return (e?.target as HTMLElement | null)?.closest('[data-animate-target]')?.getAttribute('data-animate-target')
82
+ ?? null
83
+ } catch (_e) {
84
+ console.warn(`Failed to get animate target`, _e)
85
+ // noop
86
+ return null
87
+ }
88
+ }
89
+
90
+ const onHoverStart = (e: MouseEvent) => {
91
+ e?.stopPropagation()
92
+ const hoverTarget = getTarget(e)
93
+ if (!isString(hoverTarget)) {
94
+ setVariants(null)
95
+ return
96
+ }
97
+ if (isEmpty(hoverTarget)) {
98
+ setVariants(['hovered'])
99
+ return
100
+ }
101
+ setVariants(['hovered', `hovered:${hoverTarget}`])
102
+ }
103
+
104
+ const resetVariants = (e: MouseEvent) => {
105
+ e?.stopPropagation()
106
+ const hoverTarget = getTarget(e)
107
+ if (!isString(hoverTarget) || isEmpty(hoverTarget)) {
108
+ setVariants(null)
109
+ return
110
+ }
111
+ setVariants(v => v?.filter(v => !v.includes(hoverTarget)) ?? null)
112
+ }
113
+
114
+ return ({
115
+ onTapStart: (e: MouseEvent) => {
116
+ e?.stopPropagation()
117
+ const tapTarget = getTarget(e)
118
+ if (!isString(tapTarget)) {
119
+ setVariants(null)
120
+ return
121
+ }
122
+ if (isEmpty(tapTarget)) {
123
+ setVariants([
124
+ 'hovered',
125
+ 'tap',
126
+ ])
127
+ } else {
128
+ setVariants([
129
+ 'hovered',
130
+ `hovered:${tapTarget}`,
131
+ `tap:${tapTarget}`,
132
+ ])
133
+ }
134
+ },
135
+ onHoverStart,
136
+ onHoverEnd: resetVariants,
137
+ onTapCancel: resetVariants,
138
+ onTap: onHoverStart,
139
+ })
140
+ }, [setVariants])
141
+
142
+ return [variants, handlers] as const
143
+ }
@@ -0,0 +1,44 @@
1
+ import { style } from "@vanilla-extract/css";
2
+
3
+ export const topLeftBtnContainer = style({
4
+ position: 'absolute',
5
+ left: 3,
6
+ top: 6
7
+ })
8
+
9
+ export const topRightBtnContainer = style({
10
+ position: 'absolute',
11
+ top: 2,
12
+ right: 2,
13
+ selectors: {
14
+ [`:where([data-likec4-shape='browser']) &`]: {
15
+ right: 5
16
+ },
17
+ ':where([data-likec4-shape="cylinder"], [data-likec4-shape="storage"]) &': {
18
+ top: 14
19
+ },
20
+ ':where([data-likec4-shape="queue"]) &': {
21
+ top: 1,
22
+ right: 12
23
+ }
24
+ }
25
+ })
26
+
27
+ export const bottomBtnContainer = style({
28
+ zIndex: 100,
29
+ position: 'absolute',
30
+ left: 0,
31
+ width: '100%',
32
+ bottom: 2,
33
+ display: 'flex',
34
+ flexDirection: 'row',
35
+ flexWrap: 'nowrap',
36
+ alignItems: 'center',
37
+ justifyContent: 'center',
38
+ pointerEvents: 'none',
39
+ selectors: {
40
+ [`:where([data-likec4-shape='browser']) &`]: {
41
+ bottom: 4
42
+ }
43
+ }
44
+ })
@@ -1,7 +1,7 @@
1
1
  import { rem } from '@mantine/core'
2
2
  import { createVar, fallbackVar, globalStyle, keyframes, style } from '@vanilla-extract/css'
3
3
  import { calc } from '@vanilla-extract/css-utils'
4
- import { mantine, vars, whereLight } from '../../../theme-vars'
4
+ import { mantine, vars } from '../../../theme-vars'
5
5
 
6
6
  // For framer motion
7
7
  export const containerForFramer = style({
@@ -39,16 +39,6 @@ export const nodeHandlerInCenter = style({
39
39
  visibility: 'hidden'
40
40
  })
41
41
 
42
- export const dimmed = style({})
43
-
44
- globalStyle(`.react-flow__node-compound:has(${dimmed})`, {
45
- opacity: 0.25,
46
- transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
47
- transitionDelay: '200ms',
48
- filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(1px)')}`,
49
- willChange: 'opacity, filter'
50
- })
51
-
52
42
  globalStyle(`:where([data-mantine-color-scheme='dark'] .likec4-compound-transparent)`, {
53
43
  vars: {
54
44
  ['--_compound-border-color']: `color-mix(in srgb, ${vars.compound.titleColor} 25%, ${vars.element.stroke})`
@@ -243,59 +233,6 @@ globalStyle(`:where([data-mantine-color-scheme='light'] .likec4-compound-transpa
243
233
  }
244
234
  })
245
235
 
246
- const btn = style({
247
- pointerEvents: 'all',
248
- cursor: 'pointer',
249
- color: `var(--_compound-title-color,${navigateBtnColor})`,
250
- opacity: 'var(--ai-opacity)',
251
- backgroundColor: 'var(--ai-bg)',
252
- vars: {
253
- '--ai-opacity': '1',
254
- '--ai-bg-idle': `color-mix(in srgb , ${vars.element.fill}, transparent 99%)`,
255
- '--ai-bg': `var(--ai-bg-idle)`,
256
- '--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill} 65%, ${vars.element.stroke})`,
257
- '--ai-hover': `color-mix(in srgb , ${vars.element.fill} 50%, ${vars.element.stroke})`
258
- },
259
- ':hover': {
260
- boxShadow: mantine.shadows.md
261
- },
262
- selectors: {
263
- [`${whereLight} .likec4-compound-transparent &`]: {
264
- opacity: 0.85,
265
- vars: {
266
- '--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 20%)`,
267
- '--ai-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 10%)`,
268
- '--ai-bg': `color-mix(in srgb , ${vars.element.fill}, transparent 99%)`
269
- }
270
- }
271
- }
272
- })
273
-
274
- export const navigateBtn = style([btn, {
275
- position: 'absolute',
276
- left: 3,
277
- top: 6
278
- }])
279
-
280
- export const detailsBtn = style([btn, {
281
- // position: 'absolute',
282
- // top: 2,
283
- // right: 2,
284
- // selectors: {
285
- // [`:where([data-likec4-shape='browser']) &`]: {
286
- // top: 3,
287
- // right: 5
288
- // },
289
- // ':where([data-likec4-shape="cylinder"], [data-likec4-shape="storage"]) &': {
290
- // top: 14
291
- // },
292
- // ':where([data-likec4-shape="queue"]) &': {
293
- // top: 1,
294
- // right: 12
295
- // }
296
- // }
297
- }])
298
-
299
236
  export const elementIcon = style({
300
237
  flex: `0 0 ${iconSize}`,
301
238
  height: iconSize,
@@ -1,26 +1,25 @@
1
- import { DiagramNode, type ThemeColor } from '@likec4/core'
2
- import { ActionIcon, Box, Text, Tooltip } from '@mantine/core'
1
+ import { type ThemeColor, DiagramNode } from '@likec4/core'
2
+ import { Box, Text } from '@mantine/core'
3
3
  import { useDebouncedValue } from '@mantine/hooks'
4
- import { IconId, IconZoomScan } from '@tabler/icons-react'
5
4
  import { assignInlineVars } from '@vanilla-extract/dynamic'
6
- import { Handle, type NodeProps, Position } from '@xyflow/react'
5
+ import { type NodeProps, Handle, Position } from '@xyflow/react'
7
6
  import clsx from 'clsx'
8
7
  import { deepEqual as eq } from 'fast-equals'
9
- import { m, type Variants } from 'framer-motion'
10
- import { memo, useCallback, useState } from 'react'
8
+ import { m } from 'framer-motion'
9
+ import { memo, useState } from 'react'
11
10
  import { clamp } from 'remeda'
11
+ import { ActionButtonBar } from '../../../controls/action-button-bar/ActionButtonBar'
12
+ import { NavigateToButton, OpenDetailsButton } from '../../../controls/action-buttons/ActionButtons'
12
13
  import { useDiagramState } from '../../../hooks/useDiagramState'
13
- import type { CompoundXYFlowNode } from '../../types'
14
- import { stopPropagation } from '../../utils'
14
+ import type { DiagramFlowTypes } from '../../types'
15
+ import { toDomPrecision } from '../../utils'
16
+ import { type VariantKeys, NodeVariants, useFramerAnimateVariants } from '../AnimateVariants'
17
+ import * as nodeCss from '../Node.css'
15
18
  import { ElementIcon } from '../shared/ElementIcon'
16
19
  import { CompoundToolbar } from '../shared/Toolbar'
17
- import { useFramerAnimateVariants } from '../use-animate-variants'
18
20
  import * as css from './CompoundNode.css'
19
21
 
20
- type CompoundNodeProps = Pick<
21
- NodeProps<CompoundXYFlowNode>,
22
- 'id' | 'data' | 'selected' | 'dragging'
23
- >
22
+ type CompoundNodeProps = NodeProps<DiagramFlowTypes.CompoundNode>
24
23
 
25
24
  const isEqualProps = (prev: CompoundNodeProps, next: CompoundNodeProps) => (
26
25
  prev.id === next.id
@@ -29,83 +28,6 @@ const isEqualProps = (prev: CompoundNodeProps, next: CompoundNodeProps) => (
29
28
  && eq(prev.data, next.data)
30
29
  )
31
30
 
32
- const VariantsRoot = {
33
- idle: (_, { translateZ }) => ({
34
- // Why? translateZ is used to determine state
35
- ...translateZ !== 0 && {
36
- transition: {
37
- delayChildren: .08
38
- }
39
- },
40
- transitionEnd: {
41
- translateZ: 0
42
- }
43
- }),
44
- selected: {},
45
- hovered: (_, { translateZ }) => ({
46
- ...translateZ !== 1 && {
47
- transition: {
48
- delayChildren: .08
49
- }
50
- },
51
- transitionEnd: {
52
- translateZ: 1
53
- }
54
- }),
55
- tap: {}
56
- } satisfies Variants
57
-
58
- const VariantsNavigate = {
59
- idle: {
60
- '--ai-bg': 'var(--ai-bg-idle)',
61
- scale: 1,
62
- opacity: 0.8,
63
- originX: 1,
64
- originY: 0.25,
65
- translateX: 0,
66
- translateY: 0
67
- },
68
- selected: {},
69
- hovered: {
70
- '--ai-bg': 'var(--ai-bg-hover)',
71
- scale: 1.25,
72
- opacity: 1,
73
- translateX: -1
74
- },
75
- 'hovered:navigate': {
76
- scale: 1.42
77
- },
78
- 'hovered:details': {},
79
- 'tap:navigate': {
80
- scale: 1.15
81
- }
82
- } satisfies Variants
83
- VariantsNavigate['selected'] = VariantsNavigate.hovered
84
- VariantsNavigate['hovered:details'] = VariantsNavigate.idle
85
-
86
- const VariantsDetailsBtn = {
87
- idle: {
88
- '--ai-bg': 'var(--ai-bg-idle)',
89
- scale: 1,
90
- opacity: 0.3,
91
- originX: 0.45,
92
- originY: 0.55
93
- },
94
- selected: {},
95
- hovered: {
96
- scale: 1.2,
97
- opacity: 0.6
98
- },
99
- 'hovered:details': {
100
- scale: 1.42,
101
- opacity: 1
102
- },
103
- 'tap:details': {
104
- scale: 1.15
105
- }
106
- } satisfies Variants
107
- VariantsDetailsBtn['selected'] = VariantsDetailsBtn['hovered']
108
-
109
31
  export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>((
110
32
  {
111
33
  id,
@@ -113,41 +35,37 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>((
113
35
  dragging = false,
114
36
  data: {
115
37
  isViewGroup,
116
- element
117
- }
118
- }
38
+ element,
39
+ },
40
+ width,
41
+ height,
42
+ },
119
43
  ) => {
120
44
  const modelRef = DiagramNode.modelRef(element)
121
45
  const { depth, style, color } = element
122
46
  const isNotViewGroup = !isViewGroup
123
47
  const opacity = clamp((style.opacity ?? 100) / 100, {
124
48
  min: 0,
125
- max: 1
49
+ max: 1,
126
50
  })
127
51
  const MAX_TRANSPARENCY = 40
128
52
  const borderTransparency = clamp(MAX_TRANSPARENCY - opacity * MAX_TRANSPARENCY, {
129
53
  min: 0,
130
- max: MAX_TRANSPARENCY
54
+ max: MAX_TRANSPARENCY,
131
55
  })
132
56
 
133
57
  const {
134
58
  viewId,
135
- triggerOnNavigateTo,
136
- openOverlay,
137
59
  isEditable,
138
- isHovered,
139
60
  isDimmed,
140
61
  isInteractive,
141
62
  isNavigable,
142
63
  renderIcon,
143
64
  isInActiveOverlay,
144
- enableElementDetails
65
+ enableElementDetails,
145
66
  } = useDiagramState(s => ({
146
67
  viewId: s.view.id,
147
- triggerOnNavigateTo: s.triggerOnNavigateTo,
148
- openOverlay: s.openOverlay,
149
68
  isEditable: s.readonly !== true,
150
- isHovered: s.hoveredNodeId === id,
151
69
  isDimmed: s.dimmed.has(id),
152
70
  isInteractive: s.nodesDraggable || s.nodesSelectable || s.enableElementDetails
153
71
  || (!!s.onNavigateTo && !!element.navigateTo),
@@ -155,91 +73,90 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>((
155
73
  isNavigable: isNotViewGroup && !!s.onNavigateTo && !!element.navigateTo,
156
74
  renderIcon: s.renderIcon,
157
75
  isInActiveOverlay: (s.activeOverlay?.elementDetails ?? s.activeOverlay?.relationshipsOf) === id,
158
- enableElementDetails: isNotViewGroup && s.enableElementDetails
76
+ enableElementDetails: isNotViewGroup && s.enableElementDetails,
159
77
  }))
160
- const _isToolbarVisible = isNotViewGroup && isEditable && (isHovered || (import.meta.env.DEV && selected))
161
- const [isToolbarVisible] = useDebouncedValue(_isToolbarVisible, _isToolbarVisible ? 500 : 300)
162
78
 
163
- const [animateVariants, animateHandlers] = useFramerAnimateVariants()
79
+ const w = toDomPrecision(width ?? element.width)
80
+ const h = toDomPrecision(height ?? element.height)
164
81
 
165
- let animate: keyof typeof VariantsRoot
82
+ let animateVariant: VariantKeys | string[]
166
83
  switch (true) {
167
84
  case isInActiveOverlay:
168
- animate = 'idle'
85
+ animateVariant = 'idle'
169
86
  break
170
87
  case dragging && selected:
171
- animate = 'selected'
88
+ animateVariant = 'selected'
172
89
  break
173
90
  case dragging:
174
- animate = 'idle'
91
+ animateVariant = 'idle'
175
92
  break
176
- case isInteractive && isHovered:
177
- animate = 'hovered'
93
+ case isDimmed:
94
+ animateVariant = 'dimmed'
178
95
  break
179
96
  case selected:
180
- animate = 'selected'
97
+ animateVariant = 'selected'
181
98
  break
182
99
  default:
183
- animate = 'idle'
100
+ animateVariant = 'idle'
184
101
  }
185
102
 
186
- const [previewColor, setPreviewColor] = useState<ThemeColor | null>(null)
103
+ const [animateVariants, animateHandlers] = useFramerAnimateVariants()
104
+ if (!dragging && !isInActiveOverlay) {
105
+ animateVariant = animateVariants ?? animateVariant
106
+ }
107
+
108
+ const isHovered = Array.isArray(animateVariant) && animateVariant.includes('hovered')
187
109
 
188
- const onNavigateTo = useCallback((e: React.MouseEvent) => {
189
- e.stopPropagation()
190
- triggerOnNavigateTo(id, e)
191
- }, [triggerOnNavigateTo, id])
110
+ const _isToolbarVisible = isNotViewGroup && ((selected && !dragging) || isHovered)
111
+ const [isToolbarVisible] = useDebouncedValue(_isToolbarVisible, _isToolbarVisible ? 500 : 300)
192
112
 
193
- const onOpenDetails = useCallback((e: React.MouseEvent) => {
194
- e.stopPropagation()
195
- openOverlay({ elementDetails: element.id })
196
- }, [openOverlay, element])
113
+ const nodeVariants = NodeVariants(w, h, {
114
+ selectedScaleBy: 0,
115
+ hoveredScaleBy: 0,
116
+ tapScaleBy: -10,
117
+ })
118
+
119
+ const [previewColor, setPreviewColor] = useState<ThemeColor | null>(null)
197
120
 
198
121
  const elementIcon = ElementIcon({
199
122
  element,
200
123
  viewId,
201
124
  className: css.elementIcon,
202
- renderIcon
125
+ renderIcon,
203
126
  })
204
127
 
205
128
  return (
206
129
  <>
207
- {isToolbarVisible && (
130
+ {isEditable && (
208
131
  <CompoundToolbar
209
- isVisible
132
+ isVisible={isToolbarVisible}
210
133
  element={element}
211
134
  align="start"
212
135
  onColorPreview={setPreviewColor} />
213
136
  )}
214
137
  <Box
215
138
  component={m.div}
216
- variants={VariantsRoot}
139
+ variants={nodeVariants}
217
140
  key={`${viewId}:element:${id}`}
218
141
  layoutId={`${viewId}:element:${id}`}
219
142
  className={css.containerForFramer}>
220
143
  <Box
221
144
  component={m.div}
222
- variants={VariantsRoot}
223
- initial={false}
224
- animate={(isHovered && !dragging && !isInActiveOverlay) ? (animateVariants ?? animate) : animate}
225
145
  className={clsx(
226
146
  css.container,
227
147
  'likec4-compound-node',
228
148
  opacity < 1 && 'likec4-compound-transparent',
229
- isDimmed && css.dimmed
230
149
  )}
150
+ initial={false}
151
+ variants={nodeVariants}
152
+ animate={animateVariant}
153
+ {...isInteractive && animateHandlers}
231
154
  mod={{
232
155
  'animate-target': '',
233
156
  'compound-depth': depth,
234
157
  'likec4-color': previewColor ?? color,
235
- hovered: isHovered
236
158
  }}
237
159
  tabIndex={-1}
238
- {...(isInteractive && {
239
- onTapStart: animateHandlers.onTapStart,
240
- onTap: animateHandlers.onTap,
241
- onTapCancel: animateHandlers.onTapCancel
242
- })}
243
160
  >
244
161
  <svg className={css.indicator}>
245
162
  <rect
@@ -254,29 +171,29 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>((
254
171
  className={clsx(
255
172
  css.compoundBody,
256
173
  opacity < 1 && css.transparent,
257
- 'likec4-compound'
174
+ 'likec4-compound',
258
175
  )}
259
176
  style={{
260
177
  ...(opacity < 1 && {
261
178
  ...assignInlineVars({
262
179
  [css.varBorderTransparency]: `${borderTransparency}%`,
263
- [css.varOpacity]: opacity.toFixed(2)
180
+ [css.varOpacity]: opacity.toFixed(2),
264
181
  }),
265
182
  ...style.border === 'none'
266
183
  ? {
267
- borderColor: 'transparent'
184
+ borderColor: 'transparent',
268
185
  }
269
186
  : {
270
- borderStyle: style.border ?? 'dashed'
271
- }
272
- })
187
+ borderStyle: style.border ?? 'dashed',
188
+ },
189
+ }),
273
190
  }}
274
191
  >
275
192
  <Box
276
193
  className={clsx(
277
194
  css.compoundTitle,
278
195
  isNavigable && css.withNavigation,
279
- 'likec4-compound-title'
196
+ 'likec4-compound-title',
280
197
  )}>
281
198
  {elementIcon}
282
199
  <Text
@@ -287,48 +204,18 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>((
287
204
  {element.title}
288
205
  </Text>
289
206
  {enableElementDetails && !!modelRef && (
290
- <Tooltip
291
- fz="xs"
292
- color="dark"
293
- label="Open details"
294
- withinPortal={false}
295
- offset={2}
296
- openDelay={600}>
297
- <ActionIcon
298
- key={`${id}details`}
299
- component={m.div}
300
- variants={VariantsDetailsBtn}
301
- data-animate-target="details"
302
- className={clsx('nodrag nopan', css.detailsBtn)}
303
- radius="md"
304
- style={{ zIndex: 100 }}
305
- role="button"
306
- onClick={onOpenDetails}
307
- onDoubleClick={stopPropagation}
308
- {...isInteractive && animateHandlers}
309
- >
310
- <IconId stroke={1.8} style={{ width: '75%' }} />
311
- </ActionIcon>
312
- </Tooltip>
207
+ <Box className={clsx(nodeCss.topRightBtnContainer)}>
208
+ <OpenDetailsButton fqn={modelRef} {...isInteractive && animateHandlers} />
209
+ </Box>
313
210
  )}
314
211
  </Box>
315
212
  </Box>
316
213
  {isNavigable && (
317
- <ActionIcon
318
- key={`${id}navigate`}
319
- component={m.div}
320
- variants={VariantsNavigate}
321
- data-animate-target="navigate"
322
- className={clsx('nodrag nopan', css.navigateBtn)}
323
- radius="md"
324
- style={{ zIndex: 100 }}
325
- onClick={onNavigateTo}
326
- role="button"
327
- onDoubleClick={stopPropagation}
328
- {...isInteractive && animateHandlers}
329
- >
330
- <IconZoomScan style={{ width: '75%' }} />
331
- </ActionIcon>
214
+ <Box className={clsx(nodeCss.topLeftBtnContainer)}>
215
+ <ActionButtonBar shiftX="left">
216
+ <NavigateToButton xynodeId={id} {...isInteractive && animateHandlers} />
217
+ </ActionButtonBar>
218
+ </Box>
332
219
  )}
333
220
  </Box>
334
221
  </Box>
@@ -16,12 +16,11 @@ import clsx from 'clsx'
16
16
  import { useId } from 'react'
17
17
  import { clamp } from 'remeda'
18
18
  import { useMantinePortalProps } from '../../../hooks/useMantinePortalProps'
19
- import { type DiagramState } from '../../../state/diagramStore'
20
- import type { XYFlowNode } from '../../types'
21
19
  import { elementLink, trigger } from './ElementLink.css'
20
+ import type { DiagramFlowTypes } from '../../types'
22
21
 
23
22
  type ElementLinkProps = {
24
- element: XYFlowNode['data']['element']
23
+ element: DiagramFlowTypes.Node['data']['element']
25
24
  }
26
25
 
27
26
  const stopEventPropagation = (e: React.MouseEvent) => e.stopPropagation()