@likec4/diagram 1.12.2 → 1.13.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 (49) hide show
  1. package/package.json +8 -8
  2. package/src/LikeC4CustomColors.tsx +2 -2
  3. package/src/LikeC4Diagram.props.ts +15 -7
  4. package/src/LikeC4Diagram.tsx +23 -14
  5. package/src/StaticLikeC4Diagram.tsx +2 -0
  6. package/src/components/Overlay.css.ts +78 -0
  7. package/src/components/Overlay.tsx +102 -0
  8. package/src/components/OverlayContext.tsx +11 -0
  9. package/src/components/index.ts +2 -0
  10. package/src/likec4model/index.ts +1 -0
  11. package/src/likec4model/useLikeC4ElementsTree.ts +44 -0
  12. package/src/overlays/edge-details/EdgeDetailsOverlay.css.ts +13 -0
  13. package/src/overlays/edge-details/EdgeDetailsOverlay.tsx +37 -0
  14. package/src/overlays/index.tsx +33 -0
  15. package/src/overlays/relationships-of/RelationshipsOverlay.tsx +33 -0
  16. package/src/overlays/relationships-of/RelationshipsXYFlow.tsx +359 -0
  17. package/src/overlays/relationships-of/SelectElement.css.ts +18 -0
  18. package/src/overlays/relationships-of/SelectElement.tsx +133 -0
  19. package/src/overlays/relationships-of/_types.ts +56 -0
  20. package/src/overlays/relationships-of/styles.css.ts +34 -0
  21. package/src/overlays/relationships-of/use-layouted-relationships.ts +607 -0
  22. package/src/overlays/relationships-of/xyflow/CompoundNode.tsx +76 -0
  23. package/src/overlays/relationships-of/xyflow/ElementNode.tsx +130 -0
  24. package/src/overlays/relationships-of/xyflow/EmptyNode.tsx +22 -0
  25. package/src/overlays/relationships-of/xyflow/RelationshipEdge.tsx +59 -0
  26. package/src/overlays/relationships-of/xyflow/styles.css.ts +170 -0
  27. package/src/state/diagram-to-xyflow.ts +1 -1
  28. package/src/state/diagramStore.ts +119 -27
  29. package/src/ui/top-left/ChangeAutoLayoutButton.tsx +1 -1
  30. package/src/ui/top-left/ManualLayoutToolsButton.tsx +110 -0
  31. package/src/ui/top-left/TopLeftPanel.tsx +15 -31
  32. package/src/ui/top-left/_shared.ts +2 -2
  33. package/src/xyflow/EdgeMarkers.tsx +19 -0
  34. package/src/xyflow/XYFlowEvents.tsx +21 -24
  35. package/src/xyflow/XYFlowInner.tsx +6 -10
  36. package/src/xyflow/edges/EdgeLabel.tsx +6 -5
  37. package/src/xyflow/edges/RelationshipEdge.tsx +4 -3
  38. package/src/xyflow/edges/RelationshipsDropdownMenu.tsx +16 -0
  39. package/src/xyflow/edges/edges.css.ts +5 -11
  40. package/src/xyflow/nodes/compound/CompoundNode.css.ts +17 -40
  41. package/src/xyflow/nodes/compound/CompoundNode.tsx +219 -28
  42. package/src/xyflow/nodes/element/ElementLink.tsx +11 -8
  43. package/src/xyflow/nodes/element/ElementNode.tsx +211 -140
  44. package/src/xyflow/nodes/element/element.css.ts +22 -33
  45. package/src/xyflow/nodes/shared/Toolbar.tsx +81 -27
  46. package/src/xyflow/nodes/use-animate-variants.tsx +64 -0
  47. package/src/xyflow/useLayoutConstraints.ts +95 -125
  48. package/src/xyflow/utils.ts +4 -0
  49. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +0 -32
@@ -0,0 +1,110 @@
1
+ import { ActionIconGroup, Group, Popover, PopoverDropdown, type PopoverProps, PopoverTarget } from '@mantine/core'
2
+ import {
3
+ IconLayoutAlignBottom,
4
+ IconLayoutAlignCenter,
5
+ IconLayoutAlignLeft,
6
+ IconLayoutAlignMiddle,
7
+ IconLayoutAlignRight,
8
+ IconLayoutAlignTop,
9
+ IconLayoutCollage,
10
+ IconRouteOff
11
+ } from '@tabler/icons-react'
12
+ import { useDiagramStoreApi } from '../../hooks/useDiagramState'
13
+ import { ActionIcon, Tooltip } from './_shared'
14
+
15
+ const Action = ({
16
+ label,
17
+ icon,
18
+ onClick
19
+ }: {
20
+ label: string
21
+ icon: React.ReactNode
22
+ onClick: React.MouseEventHandler
23
+ }) => (
24
+ <Tooltip label={label} withinPortal={false} position="top">
25
+ <ActionIcon onClick={onClick}>
26
+ {icon}
27
+ </ActionIcon>
28
+ </Tooltip>
29
+ )
30
+
31
+ export const ManualLayoutToolsButton = (props: PopoverProps) => {
32
+ const store = useDiagramStoreApi()
33
+
34
+ return (
35
+ <Popover
36
+ position="right-start"
37
+ clickOutsideEvents={[
38
+ 'pointerdown'
39
+ ]}
40
+ radius="xs"
41
+ shadow="lg"
42
+ offset={{
43
+ mainAxis: 10
44
+ }}
45
+ {...props}>
46
+ <PopoverTarget>
47
+ <Tooltip label="Manual layouting tools" withinPortal={false} position="top-end">
48
+ <ActionIcon>
49
+ <IconLayoutCollage />
50
+ </ActionIcon>
51
+ </Tooltip>
52
+ </PopoverTarget>
53
+ <PopoverDropdown p={0}>
54
+ <Group gap={'xs'}>
55
+ <ActionIconGroup pos={'relative'}>
56
+ <Action
57
+ label="Align left"
58
+ icon={<IconLayoutAlignLeft />}
59
+ onClick={e => {
60
+ e.stopPropagation()
61
+ store.getState().align('Left')
62
+ }} />
63
+ <Action
64
+ label="Align center"
65
+ icon={<IconLayoutAlignCenter />}
66
+ onClick={e => {
67
+ e.stopPropagation()
68
+ store.getState().align('Center')
69
+ }} />
70
+ <Action
71
+ label="Align right"
72
+ icon={<IconLayoutAlignRight />}
73
+ onClick={e => {
74
+ e.stopPropagation()
75
+ store.getState().align('Right')
76
+ }} />
77
+ <Action
78
+ label="Align top"
79
+ icon={<IconLayoutAlignTop />}
80
+ onClick={e => {
81
+ e.stopPropagation()
82
+ store.getState().align('Top')
83
+ }} />
84
+ <Action
85
+ label="Align middle"
86
+ icon={<IconLayoutAlignMiddle />}
87
+ onClick={e => {
88
+ e.stopPropagation()
89
+ store.getState().align('Middle')
90
+ }} />
91
+ <Action
92
+ label="Align bottom"
93
+ icon={<IconLayoutAlignBottom />}
94
+ onClick={e => {
95
+ e.stopPropagation()
96
+ store.getState().align('Bottom')
97
+ }} />
98
+ </ActionIconGroup>
99
+ <Action
100
+ label="Reset all control points"
101
+ icon={<IconRouteOff />}
102
+ onClick={e => {
103
+ e.stopPropagation()
104
+ store.getState().resetEdgeControlPoints()
105
+ }} />
106
+ </Group>
107
+ </PopoverDropdown>
108
+ </Popover>
109
+ )
110
+ }
@@ -10,8 +10,7 @@ import {
10
10
  type PopoverProps,
11
11
  Stack,
12
12
  Text,
13
- TooltipGroup,
14
- type TooltipProps
13
+ TooltipGroup
15
14
  } from '@mantine/core'
16
15
  import {
17
16
  IconAlertTriangle,
@@ -19,8 +18,7 @@ import {
19
18
  IconChevronRight,
20
19
  IconFileSymlink,
21
20
  IconFocusCentered,
22
- IconMenu2,
23
- IconRouteOff
21
+ IconMenu2
24
22
  } from '@tabler/icons-react'
25
23
  import clsx from 'clsx'
26
24
  import { AnimatePresence, LayoutGroup, m } from 'framer-motion'
@@ -30,12 +28,14 @@ import { useMantinePortalProps } from '../../hooks/useMantinePortalProps'
30
28
  import { mantine } from '../../theme-vars'
31
29
  import { ActionIcon, Tooltip } from './_shared'
32
30
  import { ChangeAutoLayoutButton } from './ChangeAutoLayoutButton'
31
+ import { ManualLayoutToolsButton } from './ManualLayoutToolsButton'
33
32
  import * as css from './styles.css'
34
33
 
35
34
  const historySelector = (s: DiagramState) => ({
36
35
  showBurgerMenu: !!s.onBurgerMenuClick,
37
- hasStepBack: s.navigationHistoryIndex > 0,
38
- hasStepForward: s.navigationHistoryIndex < s.navigationHistory.length - 1
36
+ hasStepBack: s.showNavigationButtons && !!s.onNavigateTo && s.navigationHistoryIndex > 0,
37
+ hasStepForward: s.showNavigationButtons && !!s.onNavigateTo
38
+ && s.navigationHistoryIndex < s.navigationHistory.length - 1
39
39
  })
40
40
 
41
41
  const BackwardForwardButtons = () => {
@@ -135,22 +135,6 @@ const LayoutDriftNotification = (props: PopoverProps) => (
135
135
  </HoverCard>
136
136
  )
137
137
 
138
- const ResetControlPointsButton = (props: Omit<TooltipProps, 'label' | 'children'>) => {
139
- const store = useDiagramStoreApi()
140
-
141
- return (
142
- <Tooltip label="Reset all control points" {...props}>
143
- <ActionIcon
144
- onClick={e => {
145
- e.stopPropagation()
146
- store.getState().resetEdgeControlPoints()
147
- }}>
148
- <IconRouteOff />
149
- </ActionIcon>
150
- </Tooltip>
151
- )
152
- }
153
-
154
138
  export const TopLeftPanel = () => {
155
139
  const store = useDiagramStoreApi()
156
140
  const {
@@ -160,25 +144,25 @@ export const TopLeftPanel = () => {
160
144
  showChangeAutoLayout,
161
145
  showGoToSource,
162
146
  viewportChanged,
163
- showResetControlPoints
147
+ showManualLayoutTools
164
148
  } = useDiagramState(s => {
165
149
  const isNotWalkthrough = isNullish(s.activeWalkthrough)
166
150
  const isNotFocused = isNullish(s.focusedNodeId)
167
151
  const isNotActive = isNotWalkthrough && isNotFocused
168
152
  return ({
169
- showNavigationButtons: !!s.onBurgerMenuClick || s.showNavigationButtons && !!s.onNavigateTo,
170
- showFitDiagram: s.fitViewEnabled && s.zoomable && isNotWalkthrough,
171
- showLayoutDriftWarning: !s.readonly && s.view.hasLayoutDrift === true && isNotActive,
172
- showChangeAutoLayout: s.isEditable() && isNotActive,
173
- showGoToSource: !!s.onOpenSourceView && isNotWalkthrough,
153
+ showNavigationButtons: !!s.onBurgerMenuClick || (s.showNavigationButtons && !!s.onNavigateTo),
154
+ showFitDiagram: s.controls && s.fitViewEnabled && s.zoomable && isNotWalkthrough,
155
+ showLayoutDriftWarning: s.controls && !s.readonly && s.view.hasLayoutDrift === true && isNotActive,
156
+ showChangeAutoLayout: s.controls && s.isEditable() && isNotActive,
157
+ showGoToSource: s.controls && !!s.onOpenSourceView && isNotWalkthrough,
174
158
  viewportChanged: s.viewportChanged,
175
- showResetControlPoints: s.readonly !== true && s.experimentalEdgeEditing === true
159
+ showManualLayoutTools: s.controls && s.readonly !== true && s.experimentalEdgeEditing === true
176
160
  })
177
161
  })
178
162
  const portalProps = useMantinePortalProps()
179
163
 
180
164
  return (
181
- <TooltipGroup openDelay={500} closeDelay={150}>
165
+ <TooltipGroup openDelay={600} closeDelay={150}>
182
166
  <Stack
183
167
  className={clsx(
184
168
  'react-flow__panel',
@@ -203,7 +187,7 @@ export const TopLeftPanel = () => {
203
187
  )}
204
188
  {showChangeAutoLayout && <ChangeAutoLayoutButton {...portalProps} />}
205
189
  {showLayoutDriftWarning && <LayoutDriftNotification {...portalProps} />}
206
- {showResetControlPoints && <ResetControlPointsButton {...portalProps} />}
190
+ {showManualLayoutTools && <ManualLayoutToolsButton {...portalProps} />}
207
191
  {showFitDiagram && (
208
192
  <Tooltip label={viewportChanged ? 'Center camera' : 'Camera is centered'} {...portalProps}>
209
193
  <ActionIcon
@@ -4,8 +4,8 @@ export const Tooltip = MantineTooltip.withProps({
4
4
  color: 'dark',
5
5
  fz: 'xs',
6
6
  position: 'right',
7
- openDelay: 400,
8
- closeDelay: 150,
7
+ openDelay: 600,
8
+ closeDelay: 120,
9
9
  label: '',
10
10
  children: null,
11
11
  offset: 8
@@ -39,6 +39,24 @@ const Arrow = (props: SVGProps<SVGMarkerElement>) => (
39
39
  </marker>
40
40
  )
41
41
 
42
+ const Crow = (props: SVGProps<SVGMarkerElement>) => (
43
+ <marker
44
+ viewBox="-1 -1 12 12"
45
+ refX={8}
46
+ refY={4}
47
+ markerWidth="8"
48
+ markerHeight="8"
49
+ preserveAspectRatio="xMaxYMid meet"
50
+ orient="auto-start-reverse"
51
+ {...props}>
52
+ <path
53
+ d="M 8 0 L 0 4 L 8 8 M 8 4 L 0 4"
54
+ fill="none"
55
+ strokeWidth={1}
56
+ />
57
+ </marker>
58
+ )
59
+
42
60
  const OArrow = (props: SVGProps<SVGMarkerElement>) => (
43
61
  <marker
44
62
  viewBox="-1 -1 12 10"
@@ -139,6 +157,7 @@ const ODot = (props: SVGProps<SVGMarkerElement>) => (
139
157
 
140
158
  export const EdgeMarkers = {
141
159
  Arrow,
160
+ Crow,
142
161
  OArrow,
143
162
  Open,
144
163
  Diamond,
@@ -50,12 +50,9 @@ export function useXYFlowEvents() {
50
50
  }
51
51
 
52
52
  const lastClickWasRecent = (ms = 2000) => {
53
- const prevTimestamp = lastClickTimestamp.current
54
- lastClickTimestamp.current = Date.now()
55
- if (prevTimestamp === undefined) {
56
- return false
57
- }
58
- return prevTimestamp + ms > Date.now()
53
+ const prevTimestamp = lastClickTimestamp.current ?? 0
54
+ const now = lastClickTimestamp.current = Date.now()
55
+ return prevTimestamp + ms > now
59
56
  }
60
57
 
61
58
  return ({
@@ -68,16 +65,15 @@ export function useXYFlowEvents() {
68
65
  resetFocusAndLastClicked
69
66
  } = diagramApi.getState()
70
67
  resetFocusAndLastClicked()
71
- if (!onCanvasDblClick) {
72
- event.stopPropagation()
73
- }
74
68
  if (zoomable && viewportChanged) {
75
69
  fitDiagram()
76
70
  }
71
+ if (!onCanvasDblClick) {
72
+ event.stopPropagation()
73
+ }
77
74
  onCanvasDblClick?.(event)
78
75
  },
79
76
  onPaneClick: (event) => {
80
- console.log('onPaneClick')
81
77
  if (dbclickLock()) {
82
78
  return
83
79
  }
@@ -132,7 +128,7 @@ export function useXYFlowEvents() {
132
128
  // if we focused on a node, and clicked on another node - focus on the clicked node
133
129
  const shallChangeFocus = !!focusedNodeId && focusedNodeId !== xynode.id
134
130
  // if user clicked on the same node twice in a short time, focus on it
135
- const clickedRecently = lastClickedNodeId === xynode.id && lastClickWasRecent()
131
+ const clickedRecently = lastClickWasRecent() && lastClickedNodeId === xynode.id
136
132
 
137
133
  if (clickedRecently && !!onOpenSourceElement) {
138
134
  onOpenSourceElement(xynode.data.element.id)
@@ -141,27 +137,27 @@ export function useXYFlowEvents() {
141
137
  }
142
138
  }
143
139
 
144
- if (enableFocusMode || nodesSelectable) {
140
+ if (enableFocusMode) {
145
141
  switch (true) {
146
- case enableFocusMode && clickedRecently && focusedNodeId === xynode.id: {
142
+ case clickedRecently && focusedNodeId === xynode.id: {
147
143
  focusOnNode(false)
148
144
  fitDiagram()
149
145
  break
150
146
  }
151
- case enableFocusMode && shallChangeFocus:
152
- case enableFocusMode && clickedRecently && focusedNodeId !== xynode.id: {
147
+ case (shallChangeFocus || clickedRecently): {
153
148
  focusOnNode(xynode.id)
154
149
  break
155
150
  }
156
- case nodesSelectable: {
157
- xystore.getState().addSelectedNodes([xynode.id])
158
- break
159
- }
160
- }
161
- if (!onNodeClick) {
162
- event.stopPropagation()
163
151
  }
152
+ } else if (nodesSelectable) {
153
+ xystore.getState().addSelectedNodes([xynode.id])
154
+ }
155
+
156
+ if (!onNodeClick && (enableFocusMode || nodesSelectable)) {
157
+ event.stopPropagation()
158
+ return
164
159
  }
160
+
165
161
  onNodeClick?.(
166
162
  xynode.data.element,
167
163
  event
@@ -176,16 +172,17 @@ export function useXYFlowEvents() {
176
172
  setLastClickedNode
177
173
  } = diagramApi.getState()
178
174
  setLastClickedNode(xynode.id)
179
- lastClickTimestamp.current = Date.now()
175
+ lastClickWasRecent()
180
176
  if (isNonNullish(focusedNodeId) || enableFocusMode) {
181
177
  // if we are already focused on the node, cancel
182
178
  if (focusedNodeId === xynode.id) {
179
+ focusOnNode(false)
183
180
  fitDiagram()
184
181
  } else {
185
182
  focusOnNode(xynode.id)
186
183
  }
187
- event.stopPropagation()
188
184
  }
185
+ event.stopPropagation()
189
186
  },
190
187
  onEdgeClick: (event, xyedge) => {
191
188
  const {
@@ -1,6 +1,5 @@
1
- import { Controls } from '@xyflow/react'
2
1
  import { shallowEqual } from 'fast-equals'
3
- import { memo, type PropsWithChildren } from 'react'
2
+ import { memo } from 'react'
4
3
  import { isNonNullish } from 'remeda'
5
4
  import { useDiagramState } from '../hooks/useDiagramState'
6
5
  import type { LikeC4DiagramProperties } from '../LikeC4Diagram.props'
@@ -10,26 +9,25 @@ import NotationPanel from '../ui/notation'
10
9
  import { TopLeftPanel } from '../ui/top-left/TopLeftPanel'
11
10
  import { XYFlowBackground } from './XYFlowBackground'
12
11
 
13
- type XYFlowInnerProps = PropsWithChildren<{
12
+ type XYFlowInnerProps = {
14
13
  background: NonNullable<LikeC4DiagramProperties['background']>
15
- controls: boolean
16
14
  showDiagramTitle: boolean
17
- }>
15
+ }
18
16
 
19
17
  export const XYFlowInner = /* @__PURE__ */ memo(function XYFlowInnerR({
20
- children,
21
18
  background,
22
- controls,
23
19
  showDiagramTitle
24
20
  }: XYFlowInnerProps) {
25
21
  const {
26
22
  showNotations,
27
23
  isDynamicView,
24
+ showTopLeft,
28
25
  isDynamicViewActive,
29
26
  enableDynamicViewWalkthrough
30
27
  } = useDiagramState(s => ({
31
28
  showNotations: s.showNotations,
32
29
  isDynamicView: s.isDynamicView,
30
+ showTopLeft: s.controls || (s.showNavigationButtons && !!s.onNavigateTo) || !!s.onBurgerMenuClick,
33
31
  enableDynamicViewWalkthrough: s.enableDynamicViewWalkthrough,
34
32
  isDynamicViewActive: isNonNullish(s.activeWalkthrough)
35
33
  }))
@@ -40,12 +38,10 @@ export const XYFlowInner = /* @__PURE__ */ memo(function XYFlowInnerR({
40
38
  return (
41
39
  <>
42
40
  {isBgWithPattern && <XYFlowBackground background={background} />}
43
- {controls && <Controls showInteractive={false} position={'top-center'} />}
44
- <TopLeftPanel />
41
+ {showTopLeft && <TopLeftPanel />}
45
42
  {isDiagramTitleVisible && <DiagramTitlePanel />}
46
43
  {isDynamicView && enableDynamicViewWalkthrough && <DynamicViewWalkthrough />}
47
44
  {showNotations && <NotationPanel />}
48
- {children}
49
45
  </>
50
46
  )
51
47
  }, shallowEqual)
@@ -22,6 +22,7 @@ import { isTruthy } from 'remeda'
22
22
  import { useDiagramState, useDiagramStoreApi, useMantinePortalProps } from '../../hooks'
23
23
  import { useLikeC4Model } from '../../likec4model/useLikeC4Model'
24
24
  import type { RelationshipData } from '../types'
25
+ import { stopPropagation } from '../utils'
25
26
  import * as edgesCss from './edges.css'
26
27
  import { RelationshipsDropdownMenu } from './RelationshipsDropdownMenu'
27
28
 
@@ -125,9 +126,9 @@ const NotePopover = ({ notes, children }: PropsWithChildren<{ notes: string }>)
125
126
  <PopoverDropdown
126
127
  component={Stack}
127
128
  p={'xs'}
128
- onPointerDownCapture={e => e.stopPropagation()}
129
- onClick={e => e.stopPropagation()}
130
- onDoubleClick={e => e.stopPropagation()}
129
+ onPointerDownCapture={stopPropagation}
130
+ onClick={stopPropagation}
131
+ onDoubleClick={stopPropagation}
131
132
  >
132
133
  <ScrollAreaAutosize maw={450} mah={350} type="scroll" mx={'auto'} mt={2}>
133
134
  <Text component="div" className={edgesCss.edgeNoteText} p={4}>{notes}</Text>
@@ -171,13 +172,13 @@ function NavigateToBtn({ viewId }: NavigateToBtnProps) {
171
172
  className={clsx('nodrag nopan', edgesCss.cssNavigateBtn)}
172
173
  size={'sm'}
173
174
  radius="sm"
174
- onPointerDownCapture={e => e.stopPropagation()}
175
+ onPointerDownCapture={stopPropagation}
175
176
  onClick={event => {
176
177
  event.stopPropagation()
177
178
  diagramApi.getState().onNavigateTo?.(viewId, event)
178
179
  }}
179
180
  role="button"
180
- onDoubleClick={event => event.stopPropagation()}
181
+ onDoubleClick={stopPropagation}
181
182
  >
182
183
  <IconZoomScan className={edgesCss.cssNavigateBtnIcon} />
183
184
  </ActionIcon>
@@ -63,8 +63,9 @@ const toMarker = (arrowType?: RelationshipArrowType): EdgeMarkerType | undefined
63
63
  }
64
64
  switch (arrowType) {
65
65
  case 'normal':
66
- case 'crow':
67
66
  return 'Arrow' as const
67
+ case 'crow':
68
+ return 'Crow' as const
68
69
  case 'onormal':
69
70
  return 'OArrow' as const
70
71
  case 'diamond':
@@ -332,7 +333,7 @@ export const RelationshipEdge = memo<EdgeProps<XYFlowEdge>>(function Relationshi
332
333
  const onRmbControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>, domNode: HTMLDivElement) => {
333
334
  const { xyflow } = diagramStore.getState()
334
335
 
335
- if(controlPoints.length <= 1) {
336
+ if (controlPoints.length <= 1) {
336
337
  return
337
338
  }
338
339
 
@@ -349,7 +350,7 @@ export const RelationshipEdge = memo<EdgeProps<XYFlowEdge>>(function Relationshi
349
350
  domNode.removeEventListener('pointerup', onPointerUp, {
350
351
  capture: true
351
352
  })
352
- e.stopPropagation()
353
+ e.stopPropagation()
353
354
  }
354
355
 
355
356
  domNode.addEventListener('pointerup', onPointerUp, {
@@ -122,6 +122,22 @@ export function RelationshipsDropdownMenu({
122
122
  {nested.map(renderRelationship)}
123
123
  </>
124
124
  )}
125
+ {
126
+ /* <Box pos={'absolute'} top={5} right={6}>
127
+ <ActionIcon
128
+ size={24}
129
+ variant="light"
130
+ onClick={e => {
131
+ e.stopPropagation()
132
+ diagramApi.getState().openOverlay({
133
+ edgeDetails: edge.id
134
+ })
135
+ }}
136
+ >
137
+ <IconArrowsMaximize style={{ width: '70%' }} />
138
+ </ActionIcon>
139
+ </Box> */
140
+ }
125
141
  </MenuDropdown>
126
142
  </Menu>
127
143
  )
@@ -45,23 +45,17 @@ globalStyle(`:where(${isSelected}) ${container}[data-edge-hovered='true']`, {
45
45
  [xyvars.edge.strokeWidth]: '4'
46
46
  }
47
47
  })
48
- // globalStyle(`${container}[data-edge-hovered='true']`, {
49
- // vars: {
50
- // [xyvars.edge.stroke]: `color-mix(in srgb, ${vars.relation.lineColor}, white 35%)`
51
- // },
52
- // })
53
48
 
54
- globalStyle(`.react-flow__edges > svg`, {
49
+ globalStyle(`.likec4-diagram .react-flow__edges > svg`, {
55
50
  mixBlendMode: 'plus-lighter'
56
51
  })
57
-
58
- // globalStyle(`:where([data-mantine-color-scheme="light"]) .react-flow__edges > svg`, {
59
- // mixBlendMode: 'screen'
60
- // })
52
+ globalStyle(`:where([data-mantine-color-scheme="light"]) .likec4-diagram .react-flow__edges > svg`, {
53
+ mixBlendMode: 'screen'
54
+ })
61
55
 
62
56
  export const dimmed = style({})
63
57
 
64
- globalStyle(`.react-flow__edges > svg:has(${dimmed})`, {
58
+ globalStyle(`.likec4-diagram .react-flow__edges > svg:has(${dimmed})`, {
65
59
  opacity: 0.6,
66
60
  transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
67
61
  transitionDelay: '200ms',
@@ -8,7 +8,17 @@ export const container = style({
8
8
  height: '100%',
9
9
  position: 'relative',
10
10
  padding: 0,
11
- margin: 0
11
+ margin: 0,
12
+ ':before': {
13
+ content: ' ',
14
+ position: 'absolute',
15
+ top: 0,
16
+ left: -16,
17
+ width: 16,
18
+ height: 'min(100%, 80px)',
19
+ pointerEvents: 'all',
20
+ background: 'transparent'
21
+ }
12
22
  })
13
23
 
14
24
  export const nodeHandlerInCenter = style({
@@ -59,7 +69,7 @@ export const compoundBody = style({
59
69
  }
60
70
  },
61
71
  ':before': {
62
- content: '" "',
72
+ content: ' ',
63
73
  position: 'absolute',
64
74
  top: 0,
65
75
  left: 0,
@@ -185,10 +195,6 @@ globalStyle(`${indicator} rect`, {
185
195
  fill: 'none'
186
196
  })
187
197
 
188
- // globalStyle(`:where(.react-flow__node:focus-within:not(.selected)) ${indicator} rect`, {
189
- // stroke: `color-mix(in srgb, ${vars.element.stroke} 30%, ${vars.element.loContrast})`,
190
- // strokeWidth: 8
191
- // })
192
198
  const navigateBtnColor = createVar('navigateBtnColor')
193
199
 
194
200
  globalStyle(`${container}`, {
@@ -209,26 +215,17 @@ export const navigateBtn = style({
209
215
  top: 6,
210
216
  cursor: 'pointer',
211
217
  color: `var(--_compound-title-color,${navigateBtnColor})`,
212
- transformOrigin: '90% 50%',
213
- opacity: 0.75,
214
- transition: 'all 150ms ease-out',
215
- transitionDelay: '0ms',
218
+ opacity: 'var(--ai-opacity)',
216
219
  backgroundColor: 'var(--ai-bg)',
217
220
  vars: {
218
- '--ai-bg': `color-mix(in srgb , ${vars.element.fill}, transparent 99%)`,
221
+ '--ai-opacity': '0.75',
222
+ '--ai-bg-idle': `color-mix(in srgb , ${vars.element.fill}, transparent 99%)`,
223
+ '--ai-bg': `var(--ai-bg-idle)`,
219
224
  '--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill} 65%, ${vars.element.stroke})`,
220
225
  '--ai-hover': `color-mix(in srgb , ${vars.element.fill} 50%, ${vars.element.stroke})`
221
226
  },
222
227
  ':hover': {
223
- boxShadow: mantine.shadows.lg,
224
- transform: 'scale(1.42)',
225
- opacity: 1,
226
- transitionDelay: '0'
227
- },
228
- ':active': {
229
- transform: 'scale(1.1)',
230
- opacity: 1,
231
- transitionDelay: '0'
228
+ boxShadow: mantine.shadows.md
232
229
  },
233
230
  selectors: {
234
231
  [`:where([data-mantine-color-scheme='light'] .likec4-compound-transparent) &`]: {
@@ -237,26 +234,6 @@ export const navigateBtn = style({
237
234
  '--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 60%)`,
238
235
  '--ai-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 20%)`
239
236
  }
240
- },
241
- [`:where(.react-flow__node:not(.dragging) ${container}:hover) &:not(:hover)`]: {
242
- boxShadow: mantine.shadows.lg,
243
- transform: 'scale(1.223)',
244
- opacity: 1,
245
- transitionDelay: '250ms',
246
- vars: {
247
- '--ai-bg': 'var(--ai-bg-hover)'
248
- }
249
237
  }
250
238
  }
251
239
  })
252
- globalStyle(`${navigateBtn} svg.icon`, {
253
- width: '75%',
254
- height: '75%',
255
- strokeWidth: 1.5
256
- })
257
-
258
- // globalStyle(`:where(.react-flow__node:not(.dragging)) ${cssIndicator}`, {
259
- // visibility: 'visible',
260
- // ":hover": {
261
- // }
262
- // })