@likec4/diagram 1.3.0 → 1.5.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.
- package/dist/LikeC4Diagram.css.d.ts +0 -1
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.props.d.ts +7 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1580 -1194
- package/dist/state/DiagramContext.d.ts +97 -4169
- package/dist/state/diagramStore.d.ts +98 -4172
- package/dist/state/hooks.d.ts +4 -0
- package/dist/state/index.d.ts +1 -3
- package/dist/state/useDiagramStore.d.ts +3 -4622
- package/dist/state/useNavigationHistory.d.ts +5 -0
- package/dist/style.css +217 -159
- package/dist/theme.css.d.ts +5 -0
- package/dist/ui/BackwardForwardPanel.css.d.ts +1 -0
- package/dist/ui/BackwardForwardPanel.d.ts +1 -0
- package/dist/ui/DiagramTitlePanel.css.d.ts +1 -1
- package/dist/ui/OptionsPanel.d.ts +1 -3
- package/dist/ui/options/EdgeOptions.d.ts +19 -0
- package/dist/ui/options/NodeOptions.d.ts +2 -2
- package/dist/xyflow/EdgeMarkers.d.ts +11 -0
- package/dist/xyflow/XYFlowEvents.d.ts +12 -9
- package/dist/xyflow/XYFlowInner.d.ts +1 -0
- package/dist/xyflow/const.d.ts +3 -3
- package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
- package/dist/xyflow/edges/RelationshipEdge.d.ts +4 -3
- package/dist/xyflow/edges/edges.css.d.ts +1 -0
- package/dist/xyflow/edges/utils.d.ts +1 -0
- package/dist/xyflow/hooks/index.d.ts +3 -2
- package/dist/xyflow/hooks/useXYFlow.d.ts +22 -21
- package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +1 -0
- package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -4
- package/dist/xyflow/nodes/element/element.css.d.ts +3 -1
- package/dist/xyflow/types.d.ts +2 -32
- package/package.json +21 -21
- package/src/LikeC4Diagram.css.ts +10 -8
- package/src/LikeC4Diagram.props.ts +12 -5
- package/src/LikeC4Diagram.tsx +43 -26
- package/src/globals.css.ts +11 -4
- package/src/index.ts +1 -1
- package/src/mantine.css.ts +2 -2
- package/src/state/DiagramContext.tsx +47 -16
- package/src/state/diagramStore.ts +89 -80
- package/src/state/hooks.ts +5 -0
- package/src/state/index.ts +1 -3
- package/src/state/useDiagramStore.ts +6 -13
- package/src/state/useNavigationHistory.ts +39 -0
- package/src/theme.css.ts +5 -0
- package/src/ui/BackwardForwardPanel.css.ts +22 -0
- package/src/ui/BackwardForwardPanel.tsx +59 -0
- package/src/ui/DiagramTitlePanel.css.ts +17 -6
- package/src/ui/DiagramTitlePanel.tsx +108 -94
- package/src/ui/DynamicViewWalkthrough.tsx +6 -4
- package/src/ui/OptionsPanel.tsx +37 -18
- package/src/ui/options/EdgeOptions.tsx +157 -0
- package/src/ui/options/NodeOptions.tsx +37 -29
- package/src/xyflow/EdgeMarkers.tsx +148 -0
- package/src/xyflow/FitviewOnDiagramChange.tsx +8 -4
- package/src/xyflow/SelectEdgesOnNodeFocus.tsx +59 -55
- package/src/xyflow/SyncWithDiagram.tsx +13 -20
- package/src/xyflow/XYFlow.tsx +2 -4
- package/src/xyflow/XYFlowEvents.tsx +48 -33
- package/src/xyflow/XYFlowInner.tsx +6 -3
- package/src/xyflow/const.ts +3 -3
- package/src/xyflow/diagram-to-xyflow.ts +18 -53
- package/src/xyflow/edges/RelationshipEdge.tsx +218 -126
- package/src/xyflow/edges/edges.css.ts +44 -26
- package/src/xyflow/edges/utils.ts +10 -0
- package/src/xyflow/hooks/index.ts +4 -2
- package/src/xyflow/hooks/useLayoutConstraints.ts +5 -5
- package/src/xyflow/hooks/useXYFlow.ts +28 -1
- package/src/xyflow/nodes/compound/CompoundNode.css.ts +41 -31
- package/src/xyflow/nodes/compound/CompoundNode.tsx +52 -53
- package/src/xyflow/nodes/element/ElementIcon.tsx +11 -22
- package/src/xyflow/nodes/element/ElementLink.tsx +11 -16
- package/src/xyflow/nodes/element/ElementNode.tsx +69 -114
- package/src/xyflow/nodes/element/element.css.ts +48 -15
- package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
- package/src/xyflow/types.ts +2 -4
- package/src/xyflow/utils.ts +3 -6
- package/dist/KeepAspectRatioContainer.d.ts +0 -9
- package/dist/icons/Clipboard.d.ts +0 -3
- package/dist/icons/Link.d.ts +0 -3
- package/dist/icons/ZoomIn.d.ts +0 -3
- package/dist/icons/index.d.ts +0 -3
- package/dist/mantine/theme.d.ts +0 -3
- package/dist/state/WhenInitialized.d.ts +0 -3
- package/dist/ui/Camera.d.ts +0 -3
- package/src/KeepAspectRatioContainer.tsx +0 -36
- package/src/icons/Clipboard.tsx +0 -24
- package/src/icons/Link.tsx +0 -23
- package/src/icons/ZoomIn.tsx +0 -25
- package/src/icons/index.ts +0 -3
- package/src/mantine/theme.ts +0 -20
- package/src/state/WhenInitialized.tsx +0 -24
- package/src/ui/Camera.tsx +0 -174
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { rem } from '@mantine/core'
|
|
2
|
-
import { createVar, fallbackVar,
|
|
2
|
+
import { createVar, fallbackVar, globalStyle, keyframes, style } from '@vanilla-extract/css'
|
|
3
3
|
import { mantine } from '../../mantine.css'
|
|
4
4
|
import { vars, xyvars } from '../../theme.css'
|
|
5
5
|
|
|
@@ -11,8 +11,8 @@ export const container = style({
|
|
|
11
11
|
[xyvars.edge.stroke]: vars.relation.lineColor,
|
|
12
12
|
[xyvars.edge.strokeSelected]: `color-mix(in srgb, ${vars.relation.lineColor}, ${mixColor} 35%)`,
|
|
13
13
|
[xyvars.edge.labelColor]: `color-mix(in srgb, ${vars.relation.labelColor}, rgba(255 255 255 / 0.85) 20%)`,
|
|
14
|
-
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent
|
|
15
|
-
[xyvars.edge.strokeWidth]: '
|
|
14
|
+
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent 40%)`,
|
|
15
|
+
[xyvars.edge.strokeWidth]: '3'
|
|
16
16
|
}
|
|
17
17
|
})
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ globalStyle(`:where([data-mantine-color-scheme="dark"]) ${container}`, {
|
|
|
20
20
|
vars: {
|
|
21
21
|
[mixColor]: `white`,
|
|
22
22
|
[xyvars.edge.labelColor]: vars.relation.labelColor,
|
|
23
|
-
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent
|
|
23
|
+
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent 50%)`
|
|
24
24
|
}
|
|
25
25
|
})
|
|
26
26
|
|
|
@@ -29,7 +29,7 @@ const isSelected = '.react-flow__edge.selected'
|
|
|
29
29
|
globalStyle(`:where(${isSelected}) ${container}`, {
|
|
30
30
|
vars: {
|
|
31
31
|
[xyvars.edge.stroke]: xyvars.edge.strokeSelected,
|
|
32
|
-
[xyvars.edge.strokeWidth]: '
|
|
32
|
+
[xyvars.edge.strokeWidth]: '3'
|
|
33
33
|
}
|
|
34
34
|
})
|
|
35
35
|
|
|
@@ -37,13 +37,13 @@ globalStyle(`${container}:is([data-edge-hovered='true'],[data-edge-active='true'
|
|
|
37
37
|
vars: {
|
|
38
38
|
// [xyvars.edge.stroke]: `color-mix(in srgb, ${vars.relation.lineColor}, ${mixColor} 35%)`,
|
|
39
39
|
[xyvars.edge.stroke]: xyvars.edge.strokeSelected,
|
|
40
|
-
[xyvars.edge.strokeWidth]: '
|
|
40
|
+
[xyvars.edge.strokeWidth]: '3'
|
|
41
41
|
}
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
globalStyle(`:where(${isSelected}) ${container}[data-edge-hovered='true']`, {
|
|
45
45
|
vars: {
|
|
46
|
-
[xyvars.edge.strokeWidth]: '
|
|
46
|
+
[xyvars.edge.strokeWidth]: '4'
|
|
47
47
|
}
|
|
48
48
|
})
|
|
49
49
|
// globalStyle(`${container}[data-edge-hovered='true']`, {
|
|
@@ -56,18 +56,22 @@ globalStyle(`.react-flow__edges > svg`, {
|
|
|
56
56
|
mixBlendMode: 'screen'
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
+
// globalStyle(`:where([data-mantine-color-scheme="light"]) .react-flow__edges > svg`, {
|
|
60
|
+
// mixBlendMode: 'screen'
|
|
61
|
+
// })
|
|
62
|
+
|
|
59
63
|
export const dimmed = style({})
|
|
60
64
|
|
|
61
65
|
globalStyle(`.react-flow__edges > svg:has(${dimmed})`, {
|
|
62
66
|
opacity: 0.8,
|
|
63
67
|
transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
|
|
64
68
|
transitionDelay: '200ms',
|
|
65
|
-
filter:
|
|
69
|
+
filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(1px)')}`,
|
|
66
70
|
willChange: 'opacity, filter'
|
|
67
71
|
})
|
|
68
72
|
|
|
69
73
|
export const edgePathBg = style({
|
|
70
|
-
strokeWidth: xyvars.edge.strokeWidth,
|
|
74
|
+
// strokeWidth: xyvars.edge.strokeWidth,
|
|
71
75
|
strokeOpacity: 0.08,
|
|
72
76
|
// transition: 'stroke-width 175ms ease-in-out',
|
|
73
77
|
// transition: 'stroke-width 175ms ease-in-out, stroke-opacity 150ms ease-out',
|
|
@@ -76,7 +80,7 @@ export const edgePathBg = style({
|
|
|
76
80
|
transitionTimingFunction: 'ease-out',
|
|
77
81
|
selectors: {
|
|
78
82
|
[`:where(${isSelected}, [data-edge-active='true'], [data-edge-hovered='true']) &`]: {
|
|
79
|
-
strokeWidth: `calc(${xyvars.edge.strokeWidth} +
|
|
83
|
+
strokeWidth: `calc(${xyvars.edge.strokeWidth} + 8)`,
|
|
80
84
|
strokeOpacity: 0.15
|
|
81
85
|
}
|
|
82
86
|
}
|
|
@@ -93,7 +97,7 @@ export const controlPoint = style({
|
|
|
93
97
|
stroke: xyvars.edge.stroke,
|
|
94
98
|
fillOpacity: 0.75,
|
|
95
99
|
strokeWidth: 1,
|
|
96
|
-
cursor: '
|
|
100
|
+
cursor: 'default',
|
|
97
101
|
pointerEvents: 'auto',
|
|
98
102
|
visibility: 'hidden',
|
|
99
103
|
':hover': {
|
|
@@ -112,13 +116,20 @@ export const controlPoint = style({
|
|
|
112
116
|
}
|
|
113
117
|
})
|
|
114
118
|
|
|
115
|
-
const
|
|
116
|
-
|
|
119
|
+
export const controlDragging = style({
|
|
120
|
+
cursor: 'grabbing'
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
globalStyle(`${controlDragging} *`, {
|
|
124
|
+
cursor: 'grabbing'
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const strokeKeyframes = keyframes({
|
|
117
128
|
'from': {
|
|
118
|
-
strokeDashoffset: 18 * 2
|
|
129
|
+
strokeDashoffset: 18 * 2 + 10
|
|
119
130
|
},
|
|
120
131
|
'to': {
|
|
121
|
-
strokeDashoffset:
|
|
132
|
+
strokeDashoffset: 10
|
|
122
133
|
}
|
|
123
134
|
})
|
|
124
135
|
|
|
@@ -126,19 +137,24 @@ export const cssEdgePath = style({
|
|
|
126
137
|
animationDuration: '800ms',
|
|
127
138
|
animationIterationCount: 'infinite',
|
|
128
139
|
animationTimingFunction: 'linear',
|
|
140
|
+
animationFillMode: 'both',
|
|
141
|
+
strokeDashoffset: 10,
|
|
129
142
|
selectors: {
|
|
130
143
|
[`:where([data-edge-hovered='true']) &`]: {
|
|
131
144
|
animationName: strokeKeyframes,
|
|
132
|
-
animationDelay: '
|
|
133
|
-
transition: 'stroke,stroke-width 130ms ease-out'
|
|
145
|
+
animationDelay: '450ms',
|
|
146
|
+
transition: 'stroke 130ms ease-out,stroke-width 130ms ease-out'
|
|
134
147
|
},
|
|
135
148
|
[`:where(${isSelected}, [data-edge-active='true']) &`]: {
|
|
136
149
|
animationName: strokeKeyframes,
|
|
137
150
|
animationDelay: '0ms',
|
|
138
|
-
transition: 'stroke,stroke-width 130ms ease-out'
|
|
151
|
+
transition: 'stroke 130ms ease-out,stroke-width 130ms ease-out'
|
|
139
152
|
},
|
|
140
153
|
[`:where([data-edge-dir='back']) &`]: {
|
|
141
154
|
animationDirection: 'reverse'
|
|
155
|
+
},
|
|
156
|
+
[`${dimmed} &`]: {
|
|
157
|
+
animationPlayState: 'paused'
|
|
142
158
|
}
|
|
143
159
|
}
|
|
144
160
|
})
|
|
@@ -151,29 +167,31 @@ const varTranslate = createVar('translate')
|
|
|
151
167
|
export const edgeLabel = style({
|
|
152
168
|
top: 0,
|
|
153
169
|
left: 0,
|
|
170
|
+
padding: '2px 4px 4px 4px',
|
|
154
171
|
fontFamily: vars.likec4.font,
|
|
155
172
|
position: 'absolute',
|
|
156
173
|
pointerEvents: 'all',
|
|
157
174
|
cursor: 'pointer',
|
|
175
|
+
width: 'fit-content',
|
|
158
176
|
transformOrigin: '50% 50%',
|
|
159
177
|
mixBlendMode: 'screen',
|
|
160
178
|
color: xyvars.edge.labelColor,
|
|
161
179
|
backgroundColor: xyvars.edge.labelBgColor,
|
|
162
|
-
borderRadius:
|
|
180
|
+
borderRadius: 3,
|
|
163
181
|
transform: varTranslate,
|
|
164
182
|
vars: {
|
|
165
183
|
[varTranslate]: `translate(${fallbackVar(varLabelX, '-50%')}, ${fallbackVar(varLabelY, '-50%')})`
|
|
166
184
|
},
|
|
167
185
|
selectors: {
|
|
168
186
|
'&[data-edge-hovered="true"]': {
|
|
169
|
-
transition: 'all 140ms ease-out',
|
|
170
|
-
transform: `${varTranslate} scale(1.
|
|
187
|
+
transition: 'all 140ms ease-in-out',
|
|
188
|
+
transform: `${varTranslate} scale(1.12)`
|
|
171
189
|
},
|
|
172
190
|
[`&:is(${dimmed})`]: {
|
|
173
|
-
opacity: 0.
|
|
191
|
+
opacity: 0.6,
|
|
174
192
|
transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
|
|
175
193
|
transitionDelay: '200ms',
|
|
176
|
-
filter:
|
|
194
|
+
filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(1px)')}`,
|
|
177
195
|
willChange: 'opacity, filter'
|
|
178
196
|
}
|
|
179
197
|
}
|
|
@@ -203,8 +221,8 @@ export const stepEdgeNumber = style({
|
|
|
203
221
|
})
|
|
204
222
|
|
|
205
223
|
export const edgeLabelText = style({
|
|
206
|
-
padding: '2px 6px 4px 6px',
|
|
207
224
|
textAlign: 'left',
|
|
208
|
-
|
|
209
|
-
|
|
225
|
+
whiteSpaceCollapse: 'preserve-breaks',
|
|
226
|
+
fontSize: rem(14),
|
|
227
|
+
lineHeight: 1.185
|
|
210
228
|
})
|
|
@@ -3,6 +3,16 @@ import { Position, type XYPosition } from '@xyflow/react'
|
|
|
3
3
|
import { getNodeDimensions } from '@xyflow/system'
|
|
4
4
|
import type { InternalXYFlowNode } from '../types'
|
|
5
5
|
|
|
6
|
+
export function getNodeCenter(node: InternalXYFlowNode): XYPosition {
|
|
7
|
+
const { width, height } = getNodeDimensions(node)
|
|
8
|
+
const { x, y } = node.internals.positionAbsolute
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
x: x + width / 2,
|
|
12
|
+
y: y + height / 2
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
// this helper function returns the intersection point
|
|
7
17
|
// of the line between the center of the intersectionNode and the target node
|
|
8
18
|
export function getNodeIntersectionFromCenterToPoint(
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { invariant, isAncestor, nonNullable } from '@likec4/core'
|
|
2
2
|
import { Expression, Expression as Expr, Operator, Solver, Strength, Variable } from '@lume/kiwi'
|
|
3
|
-
import { useDebouncedCallback } from '@react-hookz/web'
|
|
4
3
|
import type { InternalNode, ReactFlowProps, XYPosition } from '@xyflow/react'
|
|
5
4
|
import { getNodeDimensions } from '@xyflow/system'
|
|
6
5
|
import { useMemo, useRef } from 'react'
|
|
7
6
|
import { isNullish } from 'remeda'
|
|
8
|
-
import { useDiagramStoreApi } from '../../state'
|
|
9
|
-
import {
|
|
7
|
+
import { useDiagramStoreApi } from '../../state/hooks'
|
|
8
|
+
import type { XYFlowInstance, XYFlowNode } from '../types'
|
|
10
9
|
import { isSamePoint } from '../utils'
|
|
11
10
|
import { useXYStoreApi, type XYStoreApi } from './useXYFlow'
|
|
12
11
|
|
|
@@ -286,7 +285,8 @@ export function useLayoutConstraints(): LayoutConstraints {
|
|
|
286
285
|
x: event.clientX,
|
|
287
286
|
y: event.clientY
|
|
288
287
|
}
|
|
289
|
-
const { xyflow } = diagramApi.getState()
|
|
288
|
+
const { xyflow, cancelSaveManualLayout } = diagramApi.getState()
|
|
289
|
+
cancelSaveManualLayout()
|
|
290
290
|
solverRef.current = createLayoutConstraints(xyflow, xyflowApi, xynode.id)
|
|
291
291
|
},
|
|
292
292
|
onNodeDrag: (_event, xynode) => {
|
|
@@ -295,7 +295,7 @@ export function useLayoutConstraints(): LayoutConstraints {
|
|
|
295
295
|
},
|
|
296
296
|
onNodeDragStop: (event, _xynode) => {
|
|
297
297
|
if (!isSamePoint(dragStartedAt.current, { x: event.clientX, y: event.clientY })) {
|
|
298
|
-
diagramApi.getState().triggerSaveManualLayout(
|
|
298
|
+
diagramApi.getState().triggerSaveManualLayout()
|
|
299
299
|
}
|
|
300
300
|
solverRef.current = undefined
|
|
301
301
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useNodesData, useReactFlow, useStore, useStoreApi } from '@xyflow/react'
|
|
2
|
-
import { shallowEqual } from 'fast-equals'
|
|
2
|
+
import { deepEqual, shallowEqual } from 'fast-equals'
|
|
3
|
+
import { useCallback } from 'react'
|
|
3
4
|
import type { XYFlowEdge, XYFlowNode, XYFlowState } from '../types'
|
|
4
5
|
|
|
5
6
|
export const useXYFlow = useReactFlow<XYFlowNode, XYFlowEdge>
|
|
@@ -18,3 +19,29 @@ export function useXYStore<StateSlice = unknown>(
|
|
|
18
19
|
}
|
|
19
20
|
export const useXYStoreApi = useStoreApi<XYFlowNode, XYFlowEdge>
|
|
20
21
|
export type XYStoreApi = ReturnType<typeof useXYStoreApi>
|
|
22
|
+
|
|
23
|
+
export function useXYEdgesData(edgeIds: string[]): Pick<XYFlowEdge, 'id' | 'data'>[] {
|
|
24
|
+
const ids = edgeIds.join(',')
|
|
25
|
+
const edgesData = useXYStore(
|
|
26
|
+
useCallback(
|
|
27
|
+
(s) => {
|
|
28
|
+
const data = [] as Pick<XYFlowEdge, 'id' | 'data'>[]
|
|
29
|
+
for (const id of edgeIds) {
|
|
30
|
+
const edge = s.edgeLookup.get(id)
|
|
31
|
+
if (edge) {
|
|
32
|
+
data.push({
|
|
33
|
+
id: edge.id,
|
|
34
|
+
data: edge.data
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return data
|
|
40
|
+
},
|
|
41
|
+
[ids]
|
|
42
|
+
),
|
|
43
|
+
deepEqual
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return edgesData
|
|
47
|
+
}
|
|
@@ -12,13 +12,19 @@ export const container = style({
|
|
|
12
12
|
margin: 0
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
+
export const nodeHandlerInCenter = style({
|
|
16
|
+
top: '50%',
|
|
17
|
+
left: '50%',
|
|
18
|
+
visibility: 'hidden'
|
|
19
|
+
})
|
|
20
|
+
|
|
15
21
|
export const dimmed = style({})
|
|
16
22
|
|
|
17
23
|
globalStyle(`.react-flow__node-compound:has(${dimmed})`, {
|
|
18
24
|
opacity: 0.25,
|
|
19
25
|
transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
|
|
20
26
|
transitionDelay: '200ms',
|
|
21
|
-
filter:
|
|
27
|
+
filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(1px)')}`,
|
|
22
28
|
willChange: 'opacity, filter'
|
|
23
29
|
})
|
|
24
30
|
|
|
@@ -37,8 +43,12 @@ export const compoundBody = style({
|
|
|
37
43
|
position: 'relative',
|
|
38
44
|
borderRadius: 6,
|
|
39
45
|
boxShadow: '0 4px 10px 0.5px rgba(0,0,0,0.1) , 0 2px 2px -1px rgba(0,0,0,0.4)',
|
|
40
|
-
padding:
|
|
46
|
+
padding: 0,
|
|
47
|
+
margin: 0,
|
|
41
48
|
transition: 'all 200ms ease-out',
|
|
49
|
+
backgroundClip: 'padding-box',
|
|
50
|
+
overflow: 'hidden',
|
|
51
|
+
cursor: 'default',
|
|
42
52
|
selectors: {
|
|
43
53
|
[`:where(.react-flow__node.selected) &`]: {
|
|
44
54
|
boxShadow: 'none'
|
|
@@ -56,11 +66,9 @@ export const compoundBody = style({
|
|
|
56
66
|
left: 0,
|
|
57
67
|
width: '100%',
|
|
58
68
|
height: '100%',
|
|
59
|
-
borderRadius: 6,
|
|
60
69
|
pointerEvents: 'none',
|
|
61
70
|
transition: 'background 175ms ease-out, opacity 175ms ease-out',
|
|
62
|
-
background: vars.element.fill
|
|
63
|
-
backgroundClip: 'padding-box'
|
|
71
|
+
background: vars.element.fill
|
|
64
72
|
}
|
|
65
73
|
})
|
|
66
74
|
|
|
@@ -68,27 +76,26 @@ const opacityDeltaOnHover = createVar('opacityDeltaOnHover')
|
|
|
68
76
|
export const transparent = style({
|
|
69
77
|
borderStyle: 'dashed',
|
|
70
78
|
borderWidth: 3,
|
|
71
|
-
padding: 6,
|
|
72
79
|
boxShadow: 'none',
|
|
73
80
|
borderColor: `color-mix(in srgb , ${vars.element.stroke}, transparent ${fallbackVar(varBorderTransparency, '10%')})`,
|
|
74
|
-
backgroundClip: 'padding-box',
|
|
75
81
|
vars: {
|
|
76
82
|
[opacityDeltaOnHover]: '0',
|
|
77
83
|
'--ai-bg': `color-mix(in srgb , ${vars.element.fill}, transparent 99%)`
|
|
78
84
|
},
|
|
79
85
|
':before': {
|
|
80
|
-
|
|
86
|
+
borderRadius: 'unset',
|
|
87
|
+
transitionDelay: '100ms',
|
|
81
88
|
opacity: calc.add(fallbackVar(varOpacity, '1'), opacityDeltaOnHover)
|
|
82
89
|
},
|
|
83
90
|
selectors: {
|
|
84
|
-
[`:where(.react-flow__node.selected) &`]: {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
91
|
+
// [`:where(.react-flow__node.selected) &`]: {
|
|
92
|
+
// vars: {
|
|
93
|
+
// [opacityDeltaOnHover]: '.05'
|
|
94
|
+
// }
|
|
95
|
+
// },
|
|
89
96
|
[`:where([data-hovered]) &`]: {
|
|
90
97
|
vars: {
|
|
91
|
-
[opacityDeltaOnHover]: '.
|
|
98
|
+
[opacityDeltaOnHover]: '.08'
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
}
|
|
@@ -96,21 +103,28 @@ export const transparent = style({
|
|
|
96
103
|
|
|
97
104
|
export const title = style({
|
|
98
105
|
fontFamily: vars.compound.font,
|
|
99
|
-
fontOpticalSizing: 'auto',
|
|
100
|
-
fontStyle: 'normal',
|
|
101
106
|
textAlign: 'left',
|
|
102
|
-
display: 'inline-block',
|
|
103
107
|
fontWeight: 600,
|
|
104
|
-
fontSize:
|
|
108
|
+
fontSize: rem(15),
|
|
105
109
|
textTransform: 'uppercase',
|
|
106
110
|
letterSpacing: '0.2px',
|
|
107
111
|
lineHeight: 1,
|
|
108
|
-
opacity: 0.75,
|
|
109
112
|
color: `var(--_compound-title-color,${vars.compound.titleColor})`,
|
|
110
|
-
paddingLeft:
|
|
113
|
+
paddingLeft: 14,
|
|
114
|
+
paddingTop: 13,
|
|
115
|
+
paddingBottom: 6,
|
|
116
|
+
mixBlendMode: 'screen',
|
|
117
|
+
selectors: {
|
|
118
|
+
[`:where(.react-flow__node.draggable) &`]: {
|
|
119
|
+
cursor: 'grab'
|
|
120
|
+
},
|
|
121
|
+
[`:where(.likec4-compound-transparent) &`]: {
|
|
122
|
+
paddingTop: 10
|
|
123
|
+
}
|
|
124
|
+
}
|
|
111
125
|
})
|
|
112
126
|
export const titleWithNavigation = style({
|
|
113
|
-
paddingLeft:
|
|
127
|
+
paddingLeft: 32
|
|
114
128
|
})
|
|
115
129
|
|
|
116
130
|
globalStyle(`:where([data-mantine-color-scheme='light'] .likec4-compound-transparent)`, {
|
|
@@ -119,10 +133,6 @@ globalStyle(`:where([data-mantine-color-scheme='light'] .likec4-compound-transpa
|
|
|
119
133
|
}
|
|
120
134
|
})
|
|
121
135
|
|
|
122
|
-
globalStyle(`:where([data-mantine-color-scheme='light'] .likec4-compound-transparent) ${title}`, {
|
|
123
|
-
opacity: 1
|
|
124
|
-
})
|
|
125
|
-
|
|
126
136
|
const indicatorKeyframes = keyframes({
|
|
127
137
|
'from': {
|
|
128
138
|
opacity: 0.6
|
|
@@ -197,10 +207,10 @@ export const navigateBtn = style({
|
|
|
197
207
|
position: 'absolute',
|
|
198
208
|
pointerEvents: 'all',
|
|
199
209
|
left: 3,
|
|
200
|
-
top:
|
|
210
|
+
top: 6,
|
|
201
211
|
cursor: 'pointer',
|
|
202
212
|
color: `var(--_compound-title-color,${navigateBtnColor})`,
|
|
203
|
-
transformOrigin: '90%
|
|
213
|
+
transformOrigin: '90% 50%',
|
|
204
214
|
opacity: 0.75,
|
|
205
215
|
transition: 'all 150ms ease-out',
|
|
206
216
|
transitionDelay: '0ms',
|
|
@@ -212,7 +222,7 @@ export const navigateBtn = style({
|
|
|
212
222
|
},
|
|
213
223
|
':hover': {
|
|
214
224
|
boxShadow: mantine.shadows.lg,
|
|
215
|
-
transform: 'scale(1.
|
|
225
|
+
transform: 'scale(1.42)',
|
|
216
226
|
opacity: 1,
|
|
217
227
|
transitionDelay: '0'
|
|
218
228
|
},
|
|
@@ -225,7 +235,7 @@ export const navigateBtn = style({
|
|
|
225
235
|
[`:where([data-mantine-color-scheme='light'] .likec4-compound-transparent) &`]: {
|
|
226
236
|
opacity: 0.85,
|
|
227
237
|
vars: {
|
|
228
|
-
'--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill}, transparent
|
|
238
|
+
'--ai-bg-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 60%)`,
|
|
229
239
|
'--ai-hover': `color-mix(in srgb , ${vars.element.fill}, transparent 20%)`
|
|
230
240
|
}
|
|
231
241
|
},
|
|
@@ -241,8 +251,8 @@ export const navigateBtn = style({
|
|
|
241
251
|
}
|
|
242
252
|
})
|
|
243
253
|
globalStyle(`${navigateBtn} svg.icon`, {
|
|
244
|
-
width: '
|
|
245
|
-
height: '
|
|
254
|
+
width: '75%',
|
|
255
|
+
height: '75%',
|
|
246
256
|
strokeWidth: 1.5
|
|
247
257
|
})
|
|
248
258
|
|
|
@@ -2,12 +2,10 @@ import { Box, Text } from '@mantine/core'
|
|
|
2
2
|
import { assignInlineVars } from '@vanilla-extract/dynamic'
|
|
3
3
|
import { Handle, type NodeProps, Position } from '@xyflow/react'
|
|
4
4
|
import clsx from 'clsx'
|
|
5
|
-
import { DEV } from 'esm-env'
|
|
6
5
|
import { deepEqual as eq } from 'fast-equals'
|
|
7
6
|
import { memo } from 'react'
|
|
8
7
|
import { clamp } from 'remeda'
|
|
9
|
-
import
|
|
10
|
-
import { useDiagramState } from '../../../state'
|
|
8
|
+
import { useDiagramState } from '../../../state/hooks'
|
|
11
9
|
import type { CompoundXYFlowNode } from '../../types'
|
|
12
10
|
import { NavigateToBtn } from '../shared/NavigateToBtn'
|
|
13
11
|
import * as css from './CompoundNode.css'
|
|
@@ -31,7 +29,6 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>(function
|
|
|
31
29
|
element
|
|
32
30
|
}
|
|
33
31
|
}) {
|
|
34
|
-
DEV && useTilg()
|
|
35
32
|
const { color, style, depth = 1, ...compound } = element
|
|
36
33
|
// const w = toDomPrecision(width ?? compound.width)
|
|
37
34
|
// const h = toDomPrecision(height ?? compound.height)
|
|
@@ -52,65 +49,67 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>(function
|
|
|
52
49
|
const isnavigable = !!compound.navigateTo && hasOnNavigateTo
|
|
53
50
|
|
|
54
51
|
return (
|
|
55
|
-
|
|
56
|
-
className={clsx(
|
|
57
|
-
css.container,
|
|
58
|
-
'likec4-compound-node',
|
|
59
|
-
opacity < 1 && 'likec4-compound-transparent',
|
|
60
|
-
isDimmed && css.dimmed
|
|
61
|
-
)}
|
|
62
|
-
mod={{
|
|
63
|
-
'compound-depth': depth,
|
|
64
|
-
'likec4-color': color,
|
|
65
|
-
hovered: isHovered
|
|
66
|
-
}}
|
|
67
|
-
>
|
|
52
|
+
<>
|
|
68
53
|
<Handle
|
|
69
54
|
type="target"
|
|
70
55
|
position={Position.Top}
|
|
71
|
-
|
|
56
|
+
className={css.nodeHandlerInCenter}
|
|
72
57
|
/>
|
|
73
|
-
<
|
|
74
|
-
<rect
|
|
75
|
-
x={0}
|
|
76
|
-
y={0}
|
|
77
|
-
width={'100%'}
|
|
78
|
-
height={'100%'}
|
|
79
|
-
rx={6}
|
|
80
|
-
/>
|
|
81
|
-
</svg>
|
|
82
|
-
<div
|
|
58
|
+
<Box
|
|
83
59
|
className={clsx(
|
|
84
|
-
css.
|
|
85
|
-
|
|
86
|
-
'likec4-compound'
|
|
60
|
+
css.container,
|
|
61
|
+
'likec4-compound-node',
|
|
62
|
+
opacity < 1 && 'likec4-compound-transparent',
|
|
63
|
+
isDimmed && css.dimmed
|
|
87
64
|
)}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}),
|
|
94
|
-
borderStyle: style.border ?? 'dashed'
|
|
95
|
-
}
|
|
96
|
-
: undefined}
|
|
65
|
+
mod={{
|
|
66
|
+
'compound-depth': depth,
|
|
67
|
+
'likec4-color': color,
|
|
68
|
+
hovered: isHovered
|
|
69
|
+
}}
|
|
97
70
|
>
|
|
98
|
-
<
|
|
99
|
-
|
|
71
|
+
<svg className={css.indicator}>
|
|
72
|
+
<rect
|
|
73
|
+
x={0}
|
|
74
|
+
y={0}
|
|
75
|
+
width={'100%'}
|
|
76
|
+
height={'100%'}
|
|
77
|
+
rx={6}
|
|
78
|
+
/>
|
|
79
|
+
</svg>
|
|
80
|
+
<div
|
|
100
81
|
className={clsx(
|
|
101
|
-
css.
|
|
102
|
-
|
|
103
|
-
'likec4-compound
|
|
104
|
-
)}
|
|
105
|
-
{
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
css.compoundBody,
|
|
83
|
+
opacity < 1 && css.transparent,
|
|
84
|
+
'likec4-compound'
|
|
85
|
+
)}
|
|
86
|
+
style={opacity < 1
|
|
87
|
+
? {
|
|
88
|
+
...assignInlineVars({
|
|
89
|
+
[css.varBorderTransparency]: `${borderTransparency}%`,
|
|
90
|
+
[css.varOpacity]: opacity.toFixed(2)
|
|
91
|
+
}),
|
|
92
|
+
borderStyle: style.border ?? 'dashed'
|
|
93
|
+
}
|
|
94
|
+
: undefined}
|
|
95
|
+
>
|
|
96
|
+
<Text
|
|
97
|
+
component="div"
|
|
98
|
+
className={clsx(
|
|
99
|
+
css.title,
|
|
100
|
+
isnavigable && css.titleWithNavigation,
|
|
101
|
+
'likec4-compound-title'
|
|
102
|
+
)}>
|
|
103
|
+
{compound.title}
|
|
104
|
+
</Text>
|
|
105
|
+
</div>
|
|
106
|
+
{isnavigable && <NavigateToBtn xynodeId={id} className={css.navigateBtn} />}
|
|
107
|
+
</Box>
|
|
109
108
|
<Handle
|
|
110
109
|
type="source"
|
|
111
|
-
position={Position.
|
|
112
|
-
|
|
110
|
+
position={Position.Top}
|
|
111
|
+
className={css.nodeHandlerInCenter}
|
|
113
112
|
/>
|
|
114
|
-
|
|
113
|
+
</>
|
|
115
114
|
)
|
|
116
115
|
}, isEqualProps)
|
|
@@ -1,43 +1,32 @@
|
|
|
1
1
|
import { assignInlineVars } from '@vanilla-extract/dynamic'
|
|
2
2
|
import clsx from 'clsx'
|
|
3
3
|
import type { XYFlowNode } from '../../types'
|
|
4
|
-
import { elementIcon,
|
|
4
|
+
import { elementIcon, iconOffsetY } from './element.css'
|
|
5
5
|
|
|
6
6
|
type ElementIconProps = {
|
|
7
7
|
node: XYFlowNode['data']['element']
|
|
8
|
-
maxWidth?: number | undefined
|
|
9
|
-
paddingX?: number | undefined
|
|
10
|
-
paddingY?: number | undefined
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
export function ElementIcon({
|
|
14
|
-
node
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return null
|
|
11
|
+
node: {
|
|
12
|
+
icon,
|
|
13
|
+
title,
|
|
14
|
+
labelBBox
|
|
19
15
|
}
|
|
20
|
-
|
|
21
|
-
if (!
|
|
16
|
+
}: ElementIconProps) {
|
|
17
|
+
if (!icon) {
|
|
22
18
|
return null
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
const firstLabelY = Math.floor(firstLabel.pt[1] - firstLabel.fontSize * 1.25)
|
|
26
|
-
const maxIconHeight = Math.floor(firstLabelY - paddingY - 16)
|
|
27
|
-
// const maxIconWidth = maxWidth ?? node.width - paddingX * 2
|
|
28
|
-
|
|
29
|
-
// const centerY = paddingY + Math.floor(maxIconHeight / 2)
|
|
30
|
-
// const centerX = Math.floor(node.width / 2)
|
|
31
|
-
|
|
32
21
|
return (
|
|
33
22
|
<div
|
|
34
23
|
className={clsx(elementIcon, 'likec4-element-icon')}
|
|
35
|
-
style={assignInlineVars({
|
|
36
|
-
|
|
24
|
+
style={assignInlineVars({ iconOffsetY }, {
|
|
25
|
+
iconOffsetY: labelBBox.y + 'px'
|
|
37
26
|
})}>
|
|
38
27
|
<img
|
|
39
|
-
src={
|
|
40
|
-
alt={
|
|
28
|
+
src={icon}
|
|
29
|
+
alt={title}
|
|
41
30
|
/>
|
|
42
31
|
</div>
|
|
43
32
|
)
|