@likec4/diagram 1.8.1 → 1.12.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 (114) hide show
  1. package/package.json +21 -45
  2. package/src/LikeC4CustomColors.props.ts +5 -0
  3. package/src/LikeC4CustomColors.tsx +37 -0
  4. package/src/LikeC4Diagram.css.ts +1 -1
  5. package/src/LikeC4Diagram.props.ts +43 -95
  6. package/src/LikeC4Diagram.tsx +21 -2
  7. package/src/LikeC4ModelProvider.tsx +49 -0
  8. package/src/StaticLikeC4Diagram.tsx +1 -0
  9. package/src/globals.css.ts +2 -3
  10. package/src/hooks/index.ts +1 -0
  11. package/src/hooks/useMantinePortalProps.ts +8 -0
  12. package/src/hooks/useXYFlow.ts +1 -2
  13. package/src/index.ts +3 -0
  14. package/src/likec4model/LikeC4ModelContext.ts +4 -0
  15. package/src/likec4model/index.ts +1 -0
  16. package/src/likec4model/useLikeC4Model.ts +55 -0
  17. package/src/mantine/EnsureMantine.tsx +1 -0
  18. package/src/state/DiagramContext.tsx +1 -0
  19. package/src/state/diagram-to-xyflow.ts +2 -3
  20. package/src/state/diagramStore.ts +185 -66
  21. package/src/{theme.css.ts → theme-vars.ts} +11 -4
  22. package/src/ui/DiagramTitlePanel.css.ts +2 -3
  23. package/src/ui/DiagramTitlePanel.tsx +17 -1
  24. package/src/ui/DynamicViewWalkthrough.css.ts +28 -2
  25. package/src/ui/DynamicViewWalkthrough.tsx +97 -52
  26. package/src/ui/OptionsPanel.css.ts +1 -2
  27. package/src/ui/OptionsPanel.tsx +1 -1
  28. package/src/ui/notation/NotationPanel.css.ts +2 -3
  29. package/src/ui/notation/NotationPanel.tsx +11 -12
  30. package/src/ui/options/NodeOptions.tsx +1 -1
  31. package/src/ui/top-left/ChangeAutoLayoutButton.tsx +20 -32
  32. package/src/ui/top-left/TopLeftPanel.tsx +128 -117
  33. package/src/ui/top-left/_shared.ts +7 -6
  34. package/src/ui/top-left/styles.css.ts +17 -8
  35. package/src/utils/vector.ts +57 -0
  36. package/src/xyflow/FitviewOnDiagramChange.tsx +5 -4
  37. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +7 -5
  38. package/src/xyflow/XYFlow.tsx +10 -11
  39. package/src/xyflow/XYFlowEvents.tsx +59 -60
  40. package/src/xyflow/XYFlowInner.tsx +5 -5
  41. package/src/xyflow/edges/EdgeLabel.tsx +185 -0
  42. package/src/xyflow/edges/RelationshipEdge.tsx +170 -137
  43. package/src/xyflow/edges/RelationshipsDropdownMenu.css.ts +60 -0
  44. package/src/xyflow/edges/RelationshipsDropdownMenu.tsx +214 -0
  45. package/src/xyflow/edges/edges.css.ts +75 -7
  46. package/src/xyflow/nodes/compound/CompoundNode.css.ts +1 -2
  47. package/src/xyflow/nodes/compound/CompoundNode.tsx +4 -4
  48. package/src/xyflow/nodes/element/ElementLink.css.ts +1 -1
  49. package/src/xyflow/nodes/element/ElementLink.tsx +3 -8
  50. package/src/xyflow/nodes/element/ElementNode.tsx +47 -4
  51. package/src/xyflow/nodes/element/element.css.ts +1 -2
  52. package/src/xyflow/types.ts +1 -24
  53. package/src/xyflow/useLayoutConstraints.ts +10 -6
  54. package/src/xyflow/utils.ts +1 -1
  55. package/dist/LikeC4Diagram.css.d.ts +0 -4
  56. package/dist/LikeC4Diagram.d.ts +0 -4
  57. package/dist/LikeC4Diagram.props.d.ts +0 -185
  58. package/dist/StaticLikeC4Diagram.d.ts +0 -4
  59. package/dist/globals.css.d.ts +0 -1
  60. package/dist/hooks/index.d.ts +0 -4
  61. package/dist/hooks/useDiagramState.d.ts +0 -6
  62. package/dist/hooks/useSetState.d.ts +0 -3
  63. package/dist/hooks/useUpdateEffect.d.ts +0 -5
  64. package/dist/hooks/useXYFlow.d.ts +0 -267
  65. package/dist/index.d.ts +0 -9
  66. package/dist/index.mjs +0 -3651
  67. package/dist/mantine/EnsureMantine.d.ts +0 -5
  68. package/dist/mantine.css.d.ts +0 -3
  69. package/dist/state/DiagramContext.d.ts +0 -1189
  70. package/dist/state/diagram-to-xyflow.d.ts +0 -12
  71. package/dist/state/diagramStore.d.ts +0 -1268
  72. package/dist/style.css +0 -2139
  73. package/dist/theme.css.d.ts +0 -63
  74. package/dist/ui/DiagramTitlePanel.css.d.ts +0 -4
  75. package/dist/ui/DiagramTitlePanel.d.ts +0 -1
  76. package/dist/ui/DynamicViewWalkthrough.css.d.ts +0 -3
  77. package/dist/ui/DynamicViewWalkthrough.d.ts +0 -1
  78. package/dist/ui/OptionsPanel.css.d.ts +0 -1
  79. package/dist/ui/OptionsPanel.d.ts +0 -1
  80. package/dist/ui/notation/NotationPanel.css.d.ts +0 -6
  81. package/dist/ui/notation/NotationPanel.d.ts +0 -1
  82. package/dist/ui/notation/index.d.ts +0 -1
  83. package/dist/ui/options/EdgeOptions.d.ts +0 -19
  84. package/dist/ui/options/NodeOptions.d.ts +0 -19
  85. package/dist/ui/top-left/ChangeAutoLayoutButton.d.ts +0 -3
  86. package/dist/ui/top-left/TopLeftPanel.d.ts +0 -4
  87. package/dist/ui/top-left/_shared.d.ts +0 -5
  88. package/dist/ui/top-left/styles.css.d.ts +0 -3
  89. package/dist/xyflow/EdgeMarkers.d.ts +0 -12
  90. package/dist/xyflow/FitviewOnDiagramChange.d.ts +0 -4
  91. package/dist/xyflow/SelectEdgesOnNodeFocus.d.ts +0 -1
  92. package/dist/xyflow/XYFlow.d.ts +0 -9
  93. package/dist/xyflow/XYFlowBackground.d.ts +0 -11
  94. package/dist/xyflow/XYFlowEvents.d.ts +0 -161
  95. package/dist/xyflow/XYFlowInner.d.ts +0 -10
  96. package/dist/xyflow/const.d.ts +0 -7
  97. package/dist/xyflow/edges/RelationshipEdge.d.ts +0 -32
  98. package/dist/xyflow/edges/edges.css.d.ts +0 -12
  99. package/dist/xyflow/edges/utils.d.ts +0 -17
  100. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +0 -11
  101. package/dist/xyflow/nodes/compound/CompoundNode.d.ts +0 -6
  102. package/dist/xyflow/nodes/compound/index.d.ts +0 -1
  103. package/dist/xyflow/nodes/element/ElementLink.css.d.ts +0 -3
  104. package/dist/xyflow/nodes/element/ElementLink.d.ts +0 -7
  105. package/dist/xyflow/nodes/element/ElementNode.d.ts +0 -6
  106. package/dist/xyflow/nodes/element/ElementShapeSvg.d.ts +0 -18
  107. package/dist/xyflow/nodes/element/element.css.d.ts +0 -19
  108. package/dist/xyflow/nodes/element/index.d.ts +0 -1
  109. package/dist/xyflow/nodes/shared/NavigateToBtn.d.ts +0 -5
  110. package/dist/xyflow/types.d.ts +0 -50
  111. package/dist/xyflow/useLayoutConstraints.d.ts +0 -9
  112. package/dist/xyflow/utils.d.ts +0 -18
  113. package/src/mantine.css.ts +0 -7
  114. package/src/reset.d.ts +0 -2
@@ -1,27 +1,28 @@
1
1
  import {
2
2
  invariant,
3
+ isStepEdgeId,
3
4
  type NonEmptyArray,
4
5
  nonexhaustive,
5
6
  nonNullable,
6
7
  type Point,
7
8
  type RelationshipArrowType
8
9
  } from '@likec4/core'
9
- import { Box } from '@mantine/core'
10
10
  import { useDebouncedEffect } from '@react-hookz/web'
11
11
  import { assignInlineVars } from '@vanilla-extract/dynamic'
12
12
  import type { EdgeProps, XYPosition } from '@xyflow/react'
13
- import { EdgeLabelRenderer } from '@xyflow/react'
14
13
  import clsx from 'clsx'
15
14
  import { curveCatmullRomOpen, line as d3line } from 'd3-shape'
16
- import { deepEqual, deepEqual as eq } from 'fast-equals'
15
+ import { deepEqual as eq } from 'fast-equals'
17
16
  import { memo, type PointerEvent as ReactPointerEvent, useEffect, useRef, useState } from 'react'
18
17
  import { first, hasAtLeast, isArray, isTruthy, last } from 'remeda'
19
18
  import { useDiagramState, useDiagramStoreApi } from '../../hooks/useDiagramState'
20
19
  import { useXYStoreApi } from '../../hooks/useXYFlow'
20
+ import { vector, VectorImpl } from '../../utils/vector'
21
21
  import { ZIndexes } from '../const'
22
22
  import { EdgeMarkers, type EdgeMarkerType } from '../EdgeMarkers'
23
- import { type RelationshipData, type XYFlowEdge } from '../types'
23
+ import { type XYFlowEdge } from '../types'
24
24
  import { bezierControlPoints } from '../utils'
25
+ import { EdgeLabel } from './EdgeLabel'
25
26
  import * as edgesCss from './edges.css'
26
27
  import { getNodeIntersectionFromCenterToPoint } from './utils'
27
28
  // import { getEdgeParams } from './utils'
@@ -103,9 +104,8 @@ const isSame = (a: number, b: number) => {
103
104
  }
104
105
 
105
106
  const isSamePoint = (a: XYPosition | Point, b: XYPosition | Point) => {
106
- const [ax, ay] = isArray(a) ? a : [a.x, a.y]
107
- const [bx, by] = isArray(b) ? b : [b.x, b.y]
108
- return isSame(ax, bx) && isSame(ay, by)
107
+ return isSame(isArray(a) ? a[0] : a.x, isArray(b) ? b[0] : b.x)
108
+ && isSame(isArray(a) ? a[1] : a.y, isArray(b) ? b[1] : b.y)
109
109
  }
110
110
 
111
111
  const sameControlPoints = (a: XYPosition[] | null, b: XYPosition[] | null) => {
@@ -123,7 +123,6 @@ const isEqualProps = (prev: EdgeProps<XYFlowEdge>, next: EdgeProps<XYFlowEdge>)
123
123
  && isSame(prev.sourceY, next.sourceY)
124
124
  && isSame(prev.targetX, next.targetX)
125
125
  && isSame(prev.targetY, next.targetY)
126
- && eq(prev.data.stepNum, next.data.stepNum)
127
126
  && eq(prev.data.label, next.data.label)
128
127
  && sameControlPoints(prev.data.controlPoints, next.data.controlPoints)
129
128
  && eq(prev.data.edge, next.data.edge)
@@ -134,7 +133,7 @@ const curve = d3line<XYPosition>()
134
133
  .x(d => d.x)
135
134
  .y(d => d.y)
136
135
 
137
- export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(function RelationshipEdgeR({
136
+ export const RelationshipEdge = memo<EdgeProps<XYFlowEdge>>(function RelationshipEdgeR({
138
137
  id,
139
138
  data,
140
139
  selected,
@@ -150,15 +149,25 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
150
149
  const [isControlPointDragging, setIsControlPointDragging] = useState(false)
151
150
  const diagramStore = useDiagramStoreApi()
152
151
  const xyflowStore = useXYStoreApi()
153
- const { isActive, isEdgePathEditable, isHovered, isDimmed, hasOpenSourceRelation } = useDiagramState(s => ({
152
+ const {
153
+ connectedToFocusedNode,
154
+ isActiveWalkthroughStep,
155
+ isEdgePathEditable,
156
+ isHovered,
157
+ isDimmed,
158
+ isActiveAsParallel
159
+ } = useDiagramState(s => ({
154
160
  isEdgePathEditable: s.readonly !== true && s.experimentalEdgeEditing === true && s.focusedNodeId === null
155
- && s.activeDynamicViewStep === null,
156
- isActive: s.focusedNodeId === source || s.focusedNodeId === target
157
- || (s.activeDynamicViewStep !== null && s.activeDynamicViewStep === data.stepNum),
161
+ && s.activeWalkthrough === null,
162
+ connectedToFocusedNode: s.focusedNodeId === source || s.focusedNodeId === target,
163
+ isActiveWalkthroughStep: s.activeWalkthrough?.stepId === data.edge.id,
164
+ // If activeWalkthrough and this edge is part of the parallel group
165
+ isActiveAsParallel: !!s.activeWalkthrough?.parallelPrefix && id.startsWith(s.activeWalkthrough.parallelPrefix),
158
166
  isHovered: s.hoveredEdgeId === id,
159
- isDimmed: s.dimmed.has(id),
160
- hasOpenSourceRelation: !!s.onOpenSourceRelation
167
+ isDimmed: s.dimmed.has(id)
161
168
  }))
169
+
170
+ const isActive = connectedToFocusedNode || isActiveWalkthroughStep
162
171
  const { nodeLookup, edgeLookup } = xyflowStore.getState()
163
172
  const sourceNode = nonNullable(nodeLookup.get(source)!, `source node ${source} not found`)
164
173
  const targetNode = nonNullable(nodeLookup.get(target)!, `target node ${target} not found`)
@@ -180,7 +189,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
180
189
 
181
190
  let controlPoints = data.controlPoints ?? bezierControlPoints(data.edge)
182
191
 
183
- const isStepEdge = data.stepNum !== null
192
+ const isStepEdge = isStepEdgeId(data.edge.id)
184
193
  const isDotted = line === 'dotted'
185
194
  const isDashed = isDotted || line === 'dashed'
186
195
 
@@ -194,7 +203,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
194
203
  let labelX = labelBBox?.x ?? 0,
195
204
  labelY = labelBBox?.y ?? 0
196
205
 
197
- const [labelPos, setLabelPosition] = useState<XYPosition>({
206
+ const [labelPos, setLabelPos] = useState<XYPosition>({
198
207
  x: label?.bbox.x ?? labelX,
199
208
  y: label?.bbox.y ?? labelY
200
209
  })
@@ -235,7 +244,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
235
244
  x: Math.round(dompoint.x),
236
245
  y: Math.round(dompoint.y)
237
246
  }
238
- setLabelPosition(current => isSamePoint(current, point) ? current : point)
247
+ setLabelPos(current => isSamePoint(current, point) ? current : point)
239
248
  }, [edgePath])
240
249
 
241
250
  useDebouncedEffect(
@@ -263,35 +272,26 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
263
272
  labelY = labelPos.y
264
273
  }
265
274
 
266
- const onControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>) => {
267
- const { domNode } = xyflowStore.getState()
268
- if (!domNode || e.pointerType !== 'mouse') {
269
- return
270
- }
275
+ const onLmbControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>, domNode: HTMLDivElement) => {
276
+ const { addSelectedEdges } = xyflowStore.getState()
271
277
  const { xyflow } = diagramStore.getState()
272
- if (e.button === 2 && controlPoints.length > 1) {
273
- const newControlPoints = controlPoints.slice()
274
- newControlPoints.splice(index, 1)
275
- e.stopPropagation()
276
- // Defer the update to avoid conflict with the pointerup event
277
- setTimeout(() => {
278
- xyflow.updateEdgeData(id, { controlPoints: newControlPoints })
279
- }, 10)
280
- return
281
- }
282
- if (e.button !== 0) {
283
- return
284
- }
278
+
279
+ addSelectedEdges([id])
280
+
285
281
  const wasCanceled = diagramStore.getState().cancelSaveManualLayout()
286
282
  e.stopPropagation()
287
283
  let hasMoved = false
288
284
  let pointer = { x: e.clientX, y: e.clientY }
289
285
 
290
286
  const onPointerMove = (e: PointerEvent) => {
291
- if (hasMoved || !isSamePoint(pointer, [e.clientX, e.clientY])) {
287
+ const clientPoint = {
288
+ x: e.clientX,
289
+ y: e.clientY
290
+ }
291
+ if (!isSamePoint(pointer, clientPoint)) {
292
292
  setIsControlPointDragging(true)
293
293
  hasMoved = true
294
- pointer = { x: e.clientX, y: e.clientY }
294
+ pointer = clientPoint
295
295
  const { x, y } = xyflow.screenToFlowPosition(pointer, { snapToGrid: false })
296
296
  xyflow.updateEdgeData(id, xyedge => {
297
297
  const cp = (xyedge.data.controlPoints ?? controlPoints).slice()
@@ -329,6 +329,105 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
329
329
  })
330
330
  }
331
331
 
332
+ const onRmbControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>, domNode: HTMLDivElement) => {
333
+ const { xyflow } = diagramStore.getState()
334
+
335
+ if(controlPoints.length <= 1) {
336
+ return
337
+ }
338
+
339
+ const onPointerUp = (e: PointerEvent) => {
340
+ const newControlPoints = controlPoints.slice()
341
+ newControlPoints.splice(index, 1)
342
+ e.stopPropagation()
343
+ // Defer the update to avoid conflict with the pointerup event
344
+ setTimeout(() => {
345
+ xyflow.updateEdgeData(id, { controlPoints: newControlPoints })
346
+ diagramStore.getState().scheduleSaveManualLayout()
347
+ }, 10)
348
+
349
+ domNode.removeEventListener('pointerup', onPointerUp, {
350
+ capture: true
351
+ })
352
+ e.stopPropagation()
353
+ }
354
+
355
+ domNode.addEventListener('pointerup', onPointerUp, {
356
+ once: true,
357
+ capture: true
358
+ })
359
+
360
+ e.stopPropagation()
361
+ }
362
+
363
+ const onControlPointerDown = (index: number, e: ReactPointerEvent<SVGCircleElement>) => {
364
+ const { domNode } = xyflowStore.getState()
365
+ if (!domNode || e.pointerType !== 'mouse') {
366
+ return
367
+ }
368
+
369
+ switch (e.button) {
370
+ case 0:
371
+ onLmbControlPointerDown(index, e, domNode)
372
+ break
373
+ case 2:
374
+ onRmbControlPointerDown(index, e, domNode)
375
+ break
376
+ }
377
+ }
378
+
379
+ const onEdgePointerDown = (e: ReactPointerEvent<SVGElement>) => {
380
+ const { domNode } = xyflowStore.getState()
381
+ const { xyflow, scheduleSaveManualLayout } = diagramStore.getState()
382
+
383
+ if (!domNode || e.pointerType !== 'mouse') {
384
+ return
385
+ }
386
+ if (e.button !== 2) {
387
+ return
388
+ }
389
+
390
+ xyflow.updateEdgeData(id, edge => {
391
+ const points: VectorImpl[] = [
392
+ new VectorImpl(sourceX, sourceY),
393
+ ...controlPoints.map(vector) || [],
394
+ new VectorImpl(targetX, targetY)
395
+ ]
396
+
397
+ let pointer = { x: e.clientX, y: e.clientY }
398
+ const newPoint = vector(xyflow.screenToFlowPosition(pointer, { snapToGrid: false }))
399
+
400
+ let insertionIndex = 0
401
+ let minDistance = Infinity
402
+ for (let i = 0; i < points.length - 1; i++) {
403
+ const a = points[i]!, b = points[i + 1]!
404
+ const fromCurrentToNext = b.sub(a)
405
+ const fromCurrentToNew = newPoint.sub(a)
406
+ const fromNextToNew = newPoint.sub(b)
407
+
408
+ // Is pointer above the current segment?
409
+ if (fromCurrentToNext.dot(fromCurrentToNew) * fromCurrentToNext.dot(fromNextToNew) < 0) {
410
+ // Calculate distance by approximating edge segment with a staight line
411
+ const distanceToEdge = Math.abs(fromCurrentToNext.cross(fromCurrentToNew).abs() / fromCurrentToNext.abs())
412
+
413
+ if (distanceToEdge < minDistance) {
414
+ minDistance = distanceToEdge
415
+ insertionIndex = i
416
+ }
417
+ }
418
+ }
419
+
420
+ const newControlPoints = edge.data.controlPoints?.slice() || []
421
+ newControlPoints.splice(insertionIndex, 0, newPoint)
422
+
423
+ return { controlPoints: newControlPoints }
424
+ })
425
+
426
+ scheduleSaveManualLayout()
427
+
428
+ e.stopPropagation()
429
+ }
430
+
332
431
  let markerStartName = toMarker(diagramEdge.tail)
333
432
  let markerEndName = toMarker(diagramEdge.head ?? 'normal')
334
433
  if (diagramEdge.dir === 'back') {
@@ -338,10 +437,11 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
338
437
  const MarkerStart = markerStartName ? EdgeMarkers[markerStartName] : null
339
438
  const MarkerEnd = markerEndName ? EdgeMarkers[markerEndName] : null
340
439
 
341
- const labelZIndex = 1 + (isHovered ? ZIndexes.Element : (edgeLookup.get(id)!.zIndex ?? ZIndexes.Edge))
342
-
343
- const relationId = first(data.edge.relations)
344
- const showOpenSourceRelation = hasOpenSourceRelation && relationId !== undefined
440
+ let labelZIndex = 1 + (isHovered ? ZIndexes.Element : (edgeLookup.get(id)!.zIndex ?? ZIndexes.Edge))
441
+ if (isEdgePathEditable && selected) {
442
+ // Move label below ControlPoints, otherwise they don't capture events
443
+ labelZIndex = (edgeLookup.get(id)!.zIndex ?? ZIndexes.Edge) - 1
444
+ }
345
445
 
346
446
  return (
347
447
  <g
@@ -353,6 +453,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
353
453
  data-likec4-color={color}
354
454
  data-edge-dir={diagramEdge.dir}
355
455
  data-edge-active={isActive}
456
+ data-edge-animated={isActive || isActiveAsParallel}
356
457
  data-edge-hovered={isHovered}>
357
458
  <path
358
459
  className={clsx('react-flow__edge-interaction')}
@@ -361,7 +462,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
361
462
  stroke={'transparent'}
362
463
  strokeWidth={interactionWidth ?? 10}
363
464
  />
364
- <g className={edgesCss.markerContext}>
465
+ <g className={edgesCss.markerContext} onPointerDown={e => onEdgePointerDown(e)}>
365
466
  <defs>
366
467
  {MarkerStart && <MarkerStart id={'start' + id} />}
367
468
  {MarkerEnd && <MarkerEnd id={'end' + id} />}
@@ -404,102 +505,34 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
404
505
  )}
405
506
  {(data.label || isStepEdge) && (
406
507
  <EdgeLabel
407
- {...({
408
- isDimmed,
409
- color,
410
- isModified,
411
- labelX,
412
- labelY,
413
- isEdgePathEditable,
414
- selected: selected ?? false,
415
- stepNum: data.stepNum,
416
- label: data.label,
417
- zIndex: labelZIndex,
418
- isHovered,
419
- isActive,
420
- isStepEdge
421
- })}
422
- onClick={showOpenSourceRelation && ((e) => {
423
- e.stopPropagation()
424
- diagramStore.getState().onOpenSourceRelation?.(relationId)
425
- })}
508
+ isDimmed={isDimmed}
509
+ edgeData={data}
510
+ className={clsx(
511
+ 'nodrag nopan',
512
+ edgesCss.container,
513
+ edgesCss.edgeLabel,
514
+ isDimmed && edgesCss.dimmed
515
+ )}
516
+ style={{
517
+ ...assignInlineVars({
518
+ [edgesCss.varLabelX]: isModified ? `calc(${labelX}px - 10%)` : `${labelX}px`,
519
+ [edgesCss.varLabelY]: isModified ? `${labelY - 5}px` : `${labelY}px`
520
+ }),
521
+ // ...(isEdgePathEditable && selected && {
522
+ // pointerEvents: 'none'
523
+ // }),
524
+ ...(label && {
525
+ maxWidth: label.bbox.width + 18
526
+ }),
527
+ zIndex: labelZIndex
528
+ }}
529
+ mod={{
530
+ 'data-likec4-color': color,
531
+ 'data-edge-hovered': isHovered && !isActiveWalkthroughStep,
532
+ 'data-edge-active': isActive
533
+ }}
426
534
  />
427
535
  )}
428
536
  </g>
429
537
  )
430
538
  }, isEqualProps)
431
-
432
- type EdgeLabelProps = {
433
- isDimmed: boolean
434
- color: string
435
- isModified: boolean
436
- labelX: number
437
- labelY: number
438
- isEdgePathEditable: boolean
439
- selected: boolean
440
- stepNum: number | null
441
- label: RelationshipData['label']
442
- isHovered: boolean
443
- isActive: boolean
444
- zIndex: number
445
- onClick: false | ((e: ReactPointerEvent<HTMLDivElement>) => void)
446
- }
447
-
448
- const EdgeLabel = ({
449
- isDimmed,
450
- color,
451
- isModified,
452
- labelX,
453
- labelY,
454
- isEdgePathEditable,
455
- selected,
456
- label,
457
- stepNum,
458
- isHovered,
459
- isActive,
460
- zIndex,
461
- onClick
462
- }: EdgeLabelProps) => {
463
- return (
464
- <EdgeLabelRenderer>
465
- <Box
466
- className={clsx([
467
- 'nodrag nopan',
468
- edgesCss.container,
469
- edgesCss.edgeLabel,
470
- isDimmed && edgesCss.dimmed
471
- ])}
472
- style={{
473
- ...assignInlineVars({
474
- [edgesCss.varLabelX]: isModified ? `calc(${labelX}px - 10%)` : `${labelX}px`,
475
- [edgesCss.varLabelY]: isModified ? `${labelY - 5}px` : `${labelY}px`
476
- }),
477
- ...(isEdgePathEditable && selected && {
478
- pointerEvents: 'none'
479
- }),
480
- ...(label && {
481
- maxWidth: label.bbox.width + 18
482
- }),
483
- zIndex
484
- }}
485
- mod={{
486
- 'data-likec4-color': color,
487
- 'data-edge-hovered': isHovered,
488
- 'data-edge-active': isActive
489
- }}
490
- onClick={onClick || undefined}
491
- >
492
- {stepNum !== null && (
493
- <Box className={edgesCss.stepEdgeNumber}>
494
- {stepNum}
495
- </Box>
496
- )}
497
- {isTruthy(label?.text) && (
498
- <Box className={edgesCss.edgeLabelText}>
499
- {label.text}
500
- </Box>
501
- )}
502
- </Box>
503
- </EdgeLabelRenderer>
504
- )
505
- }
@@ -0,0 +1,60 @@
1
+ import { style } from '@vanilla-extract/css'
2
+ import { mantine, vars } from '../../theme-vars'
3
+
4
+ export const menuDropdown = style({
5
+ minWidth: 250,
6
+ maxWidth: 'min(90vw, 500px)'
7
+ })
8
+
9
+ export const menuItemRelationship = style({
10
+ // padding: mantine.spacing.sm,
11
+ // paddingTop: mantine.spacing.xs,
12
+ // borderRadius: mantine.radius.sm,
13
+ // paddingTop: mantine.spacing.xs,
14
+ // paddingBottom: mantine.spacing.xs,
15
+ gap: 4
16
+ // cursor: 'pointer',
17
+ // ':hover': {
18
+ // borderColor: mantine.colors.gray.light,
19
+ // background: mantine.colors.gray[2]
20
+ // },
21
+
22
+ // selectors: {
23
+ // [`:where([data-mantine-color-scheme="dark"]) &`]: {
24
+ // // borderColor: mantine.colors.dark[6]
25
+ // },
26
+ // [`:where([data-mantine-color-scheme="dark"]) &:hover`]: {
27
+ // // background: mantine.colors.dark[5]
28
+ // }
29
+ // }
30
+ })
31
+
32
+ export const endpoint = style({
33
+ display: 'block',
34
+ fontSize: 10,
35
+ fontWeight: 500,
36
+ whiteSpace: 'nowrap',
37
+ padding: '2px 5px',
38
+ borderRadius: 2,
39
+ background: `color-mix(in srgb , ${vars.element.fill}, transparent 45%)`,
40
+ lineHeight: 1.1,
41
+ selectors: {
42
+ [`:where([data-mantine-color-scheme="dark"]) &`]: {
43
+ color: vars.element.loContrast
44
+ }
45
+ }
46
+ })
47
+
48
+ export const title = style({
49
+ whiteSpaceCollapse: 'preserve-breaks',
50
+ fontSize: mantine.fontSizes.sm
51
+ })
52
+ //
53
+ // export const sourceId = style({
54
+ //
55
+ // })
56
+ //
57
+ // export const targetId = style({
58
+ // fontSize: 11,
59
+ // whiteSpace: 'nowrap'
60
+ // })