1
- import { computed , defineComponent , h , provide , ref } from 'vue'
2
- import { useVModel } from '@vueuse/core'
3
- import type { Connection , EdgeComponent , EdgeUpdatable , GraphEdge , HandleType , MouseTouchEvent } from '../../types'
1
+ import { computed , defineComponent , getCurrentInstance , h , inject , provide , ref , resolveComponent , toRef } from 'vue'
2
+ import type { Connection , EdgeComponent , HandleType , MouseTouchEvent } from '../../types'
4
3
import { ConnectionMode , Position } from '../../types'
5
- import { useEdgeHooks , useHandle , useVueFlow } from '../../composables'
6
- import { EdgeId , EdgeRef } from '../../context'
4
+ import { useEdge , useEdgeHooks , useHandle , useVueFlow } from '../../composables'
5
+ import { EdgeId , EdgeRef , Slots } from '../../context'
7
6
import {
8
7
ARIA_EDGE_DESC_KEY ,
9
8
ErrorCode ,
@@ -17,18 +16,12 @@ import EdgeAnchor from './EdgeAnchor'
17
16
18
17
interface Props {
19
18
id : string
20
- type : EdgeComponent | ( ( ...args : any [ ] ) => any ) | object | false
21
- name : string
22
- selectable ?: boolean
23
- focusable ?: boolean
24
- updatable ?: EdgeUpdatable
25
- edge : GraphEdge
26
19
}
27
20
28
21
const EdgeWrapper = defineComponent ( {
29
22
name : 'Edge' ,
30
23
compatConfig : { MODE : 3 } ,
31
- props : [ 'name' , 'type' , 'id' , 'updatable' , 'selectable' , 'focusable' , 'edge '] ,
24
+ props : [ 'id ' ] ,
32
25
setup ( props : Props ) {
33
26
const {
34
27
id : vueFlowId ,
@@ -45,11 +38,18 @@ const EdgeWrapper = defineComponent({
45
38
isValidConnection,
46
39
multiSelectionActive,
47
40
disableKeyboardA11y,
41
+ elementsSelectable,
42
+ edgesUpdatable,
43
+ edgesFocusable,
48
44
} = useVueFlow ( )
49
45
50
- const hooks = useEdgeHooks ( props . edge , emits )
46
+ const { edge } = useEdge ( props . id )
51
47
52
- const edge = useVModel ( props , 'edge' )
48
+ const hooks = useEdgeHooks ( edge , emits )
49
+
50
+ const slots = inject ( Slots )
51
+
52
+ const instance = getCurrentInstance ( )
53
53
54
54
const mouseOver = ref ( false )
55
55
@@ -63,11 +63,45 @@ const EdgeWrapper = defineComponent({
63
63
64
64
const edgeEl = ref < SVGElement | null > ( null )
65
65
66
+ const isSelectable = toRef ( ( ) => ( typeof edge . selectable === 'undefined' ? elementsSelectable . value : edge . selectable ) )
67
+
68
+ const isUpdatable = toRef ( ( ) => ( typeof edge . updatable === 'undefined' ? edgesUpdatable . value : edge . updatable ) )
69
+
70
+ const isFocusable = toRef ( ( ) => ( typeof edge . focusable === 'undefined' ? edgesFocusable . value : edge . focusable ) )
71
+
66
72
provide ( EdgeId , props . id )
67
73
provide ( EdgeRef , edgeEl )
68
74
69
- const edgeClass = computed ( ( ) => ( edge . value . class instanceof Function ? edge . value . class ( edge . value ) : edge . value . class ) )
70
- const edgeStyle = computed ( ( ) => ( edge . value . style instanceof Function ? edge . value . style ( edge . value ) : edge . value . style ) )
75
+ const edgeClass = computed ( ( ) => ( edge . class instanceof Function ? edge . class ( edge ) : edge . class ) )
76
+ const edgeStyle = computed ( ( ) => ( edge . style instanceof Function ? edge . style ( edge ) : edge . style ) )
77
+
78
+ const edgeCmp = computed ( ( ) => {
79
+ const name = edge . type || 'default'
80
+
81
+ const slot = slots ?. [ `edge-${ name } ` ]
82
+ if ( slot ) {
83
+ return slot
84
+ }
85
+
86
+ let edgeType = edge . template ?? getEdgeTypes . value [ name ]
87
+
88
+ if ( typeof edgeType === 'string' ) {
89
+ if ( instance ) {
90
+ const components = Object . keys ( instance . appContext . components )
91
+ if ( components && components . includes ( name ) ) {
92
+ edgeType = resolveComponent ( name , false ) as EdgeComponent
93
+ }
94
+ }
95
+ }
96
+
97
+ if ( edgeType && typeof edgeType !== 'string' ) {
98
+ return edgeType
99
+ }
100
+
101
+ emits . error ( new VueFlowError ( ErrorCode . EDGE_TYPE_MISSING , edgeType ) )
102
+
103
+ return false
104
+ } )
71
105
72
106
const { handlePointerDown } = useHandle ( {
73
107
nodeId,
@@ -80,29 +114,29 @@ const EdgeWrapper = defineComponent({
80
114
} )
81
115
82
116
return ( ) => {
83
- const sourceNode = findNode ( edge . value . source )
84
- const targetNode = findNode ( edge . value . target )
85
- const pathOptions = 'pathOptions' in edge . value ? edge . value . pathOptions : { }
117
+ const sourceNode = findNode ( edge . source )
118
+ const targetNode = findNode ( edge . target )
119
+ const pathOptions = 'pathOptions' in edge ? edge . pathOptions : { }
86
120
87
121
if ( ! sourceNode && ! targetNode ) {
88
- emits . error ( new VueFlowError ( ErrorCode . EDGE_SOURCE_TARGET_MISSING , edge . value . id , edge . value . source , edge . value . target ) )
122
+ emits . error ( new VueFlowError ( ErrorCode . EDGE_SOURCE_TARGET_MISSING , edge . id , edge . source , edge . target ) )
89
123
90
124
return null
91
125
}
92
126
93
127
if ( ! sourceNode ) {
94
- emits . error ( new VueFlowError ( ErrorCode . EDGE_SOURCE_MISSING , edge . value . id , edge . value . source ) )
128
+ emits . error ( new VueFlowError ( ErrorCode . EDGE_SOURCE_MISSING , edge . id , edge . source ) )
95
129
96
130
return null
97
131
}
98
132
99
133
if ( ! targetNode ) {
100
- emits . error ( new VueFlowError ( ErrorCode . EDGE_TARGET_MISSING , edge . value . id , edge . value . target ) )
134
+ emits . error ( new VueFlowError ( ErrorCode . EDGE_TARGET_MISSING , edge . id , edge . target ) )
101
135
102
136
return null
103
137
}
104
138
105
- if ( ! edge . value || edge . value . hidden || sourceNode . hidden || targetNode . hidden ) {
139
+ if ( ! edge || edge . hidden || sourceNode . hidden || targetNode . hidden ) {
106
140
return null
107
141
}
108
142
@@ -113,7 +147,7 @@ const EdgeWrapper = defineComponent({
113
147
sourceNodeHandles = [ ...( sourceNode . handleBounds . source || [ ] ) , ...( sourceNode . handleBounds . target || [ ] ) ]
114
148
}
115
149
116
- const sourceHandle = getHandle ( sourceNodeHandles , edge . value . sourceHandle )
150
+ const sourceHandle = getHandle ( sourceNodeHandles , edge . sourceHandle )
117
151
118
152
let targetNodeHandles
119
153
if ( connectionMode . value === ConnectionMode . Strict ) {
@@ -122,7 +156,7 @@ const EdgeWrapper = defineComponent({
122
156
targetNodeHandles = [ ...( targetNode . handleBounds . target || [ ] ) , ...( targetNode . handleBounds . source || [ ] ) ]
123
157
}
124
158
125
- const targetHandle = getHandle ( targetNodeHandles , edge . value . targetHandle )
159
+ const targetHandle = getHandle ( targetNodeHandles , edge . targetHandle )
126
160
127
161
const sourcePosition = sourceHandle ? sourceHandle . position : Position . Bottom
128
162
@@ -137,10 +171,10 @@ const EdgeWrapper = defineComponent({
137
171
targetPosition ,
138
172
)
139
173
140
- edge . value . sourceX = sourceX
141
- edge . value . sourceY = sourceY
142
- edge . value . targetX = targetX
143
- edge . value . targetY = targetY
174
+ edge . sourceX = sourceX
175
+ edge . sourceY = sourceY
176
+ edge . targetX = targetX
177
+ edge . targetY = targetY
144
178
145
179
return h (
146
180
'g' ,
@@ -150,14 +184,14 @@ const EdgeWrapper = defineComponent({
150
184
'data-id' : props . id ,
151
185
'class' : [
152
186
'vue-flow__edge' ,
153
- `vue-flow__edge-${ props . type === false ? 'default' : props . name } ` ,
187
+ `vue-flow__edge-${ edgeCmp . value === false ? 'default' : edge . type || 'default' } ` ,
154
188
noPanClassName . value ,
155
189
edgeClass . value ,
156
190
{
157
191
updating : mouseOver . value ,
158
- selected : edge . value . selected ,
159
- animated : edge . value . animated ,
160
- inactive : ! props . selectable ,
192
+ selected : edge . selected ,
193
+ animated : edge . animated ,
194
+ inactive : ! isSelectable . value ,
161
195
} ,
162
196
] ,
163
197
'onClick' : onEdgeClick ,
@@ -166,52 +200,49 @@ const EdgeWrapper = defineComponent({
166
200
'onMouseenter' : onEdgeMouseEnter ,
167
201
'onMousemove' : onEdgeMouseMove ,
168
202
'onMouseleave' : onEdgeMouseLeave ,
169
- 'onKeyDown' : props . focusable ? onKeyDown : undefined ,
170
- 'tabIndex' : props . focusable ? 0 : undefined ,
171
- 'aria-label' :
172
- edge . value . ariaLabel === null
173
- ? undefined
174
- : edge . value . ariaLabel || `Edge from ${ edge . value . source } to ${ edge . value . target } ` ,
175
- 'aria-describedby' : props . focusable ? `${ ARIA_EDGE_DESC_KEY } -${ vueFlowId } ` : undefined ,
176
- 'role' : props . focusable ? 'button' : 'img' ,
203
+ 'onKeyDown' : isFocusable . value ? onKeyDown : undefined ,
204
+ 'tabIndex' : isFocusable . value ? 0 : undefined ,
205
+ 'aria-label' : edge . ariaLabel === null ? undefined : edge . ariaLabel || `Edge from ${ edge . source } to ${ edge . target } ` ,
206
+ 'aria-describedby' : isFocusable . value ? `${ ARIA_EDGE_DESC_KEY } -${ vueFlowId } ` : undefined ,
207
+ 'role' : isFocusable . value ? 'button' : 'img' ,
177
208
} ,
178
209
[
179
210
updating . value
180
211
? null
181
- : h ( props . type === false ? getEdgeTypes . value . default : props . type , {
212
+ : h ( edgeCmp . value === false ? getEdgeTypes . value . default : ( edgeCmp . value as any ) , {
182
213
id : props . id ,
183
214
sourceNode,
184
215
targetNode,
185
- source : edge . value . source ,
186
- target : edge . value . target ,
187
- type : edge . value . type ,
188
- updatable : props . updatable ,
189
- selected : edge . value . selected ,
190
- animated : edge . value . animated ,
191
- label : edge . value . label ,
192
- labelStyle : edge . value . labelStyle ,
193
- labelShowBg : edge . value . labelShowBg ,
194
- labelBgStyle : edge . value . labelBgStyle ,
195
- labelBgPadding : edge . value . labelBgPadding ,
196
- labelBgBorderRadius : edge . value . labelBgBorderRadius ,
197
- data : edge . value . data ,
198
- events : { ...edge . value . events , ...hooks . on } ,
216
+ source : edge . source ,
217
+ target : edge . target ,
218
+ type : edge . type ,
219
+ updatable : isUpdatable . value ,
220
+ selected : edge . selected ,
221
+ animated : edge . animated ,
222
+ label : edge . label ,
223
+ labelStyle : edge . labelStyle ,
224
+ labelShowBg : edge . labelShowBg ,
225
+ labelBgStyle : edge . labelBgStyle ,
226
+ labelBgPadding : edge . labelBgPadding ,
227
+ labelBgBorderRadius : edge . labelBgBorderRadius ,
228
+ data : edge . data ,
229
+ events : { ...edge . events , ...hooks . on } ,
199
230
style : edgeStyle . value ,
200
- markerStart : `url('#${ getMarkerId ( edge . value . markerStart , vueFlowId ) } ')` ,
201
- markerEnd : `url('#${ getMarkerId ( edge . value . markerEnd , vueFlowId ) } ')` ,
231
+ markerStart : `url('#${ getMarkerId ( edge . markerStart , vueFlowId ) } ')` ,
232
+ markerEnd : `url('#${ getMarkerId ( edge . markerEnd , vueFlowId ) } ')` ,
202
233
sourcePosition,
203
234
targetPosition,
204
235
sourceX,
205
236
sourceY,
206
237
targetX,
207
238
targetY,
208
- sourceHandleId : edge . value . sourceHandle ,
209
- targetHandleId : edge . value . targetHandle ,
210
- interactionWidth : edge . value . interactionWidth ,
239
+ sourceHandleId : edge . sourceHandle ,
240
+ targetHandleId : edge . targetHandle ,
241
+ interactionWidth : edge . interactionWidth ,
211
242
...pathOptions ,
212
243
} ) ,
213
244
[
214
- props . updatable === 'source' || props . updatable === true
245
+ isUpdatable . value === 'source' || isUpdatable . value === true
215
246
? [
216
247
h (
217
248
'g' ,
@@ -231,7 +262,7 @@ const EdgeWrapper = defineComponent({
231
262
) ,
232
263
]
233
264
: null ,
234
- props . updatable === 'target' || props . updatable === true
265
+ isUpdatable . value === 'target' || isUpdatable . value === true
235
266
? [
236
267
h (
237
268
'g' ,
@@ -265,11 +296,11 @@ const EdgeWrapper = defineComponent({
265
296
}
266
297
267
298
function onEdgeUpdate ( event : MouseTouchEvent , connection : Connection ) {
268
- hooks . emit . update ( { event, edge : edge . value , connection } )
299
+ hooks . emit . update ( { event, edge, connection } )
269
300
}
270
301
271
302
function onEdgeUpdateEnd ( event : MouseTouchEvent ) {
272
- hooks . emit . updateEnd ( { event, edge : edge . value } )
303
+ hooks . emit . updateEnd ( { event, edge } )
273
304
updating . value = false
274
305
}
275
306
@@ -280,52 +311,52 @@ const EdgeWrapper = defineComponent({
280
311
281
312
updating . value = true
282
313
283
- nodeId . value = isSourceHandle ? edge . value . target : edge . value . source
284
- handleId . value = ( isSourceHandle ? edge . value . targetHandle : edge . value . sourceHandle ) ?? ''
314
+ nodeId . value = isSourceHandle ? edge . target : edge . source
315
+ handleId . value = ( isSourceHandle ? edge . targetHandle : edge . sourceHandle ) ?? ''
285
316
286
317
edgeUpdaterType . value = isSourceHandle ? 'target' : 'source'
287
318
288
- hooks . emit . updateStart ( { event, edge : edge . value } )
319
+ hooks . emit . updateStart ( { event, edge } )
289
320
290
321
handlePointerDown ( event )
291
322
}
292
323
293
324
function onEdgeClick ( event : MouseEvent ) {
294
- const data = { event, edge : edge . value }
325
+ const data = { event, edge }
295
326
296
- if ( props . selectable ) {
327
+ if ( isSelectable . value ) {
297
328
nodesSelectionActive . value = false
298
329
299
- if ( edge . value . selected && multiSelectionActive . value ) {
300
- removeSelectedEdges ( [ edge . value ] )
330
+ if ( edge . selected && multiSelectionActive . value ) {
331
+ removeSelectedEdges ( [ edge ] )
301
332
302
333
edgeEl . value ?. blur ( )
303
334
} else {
304
- addSelectedEdges ( [ edge . value ] )
335
+ addSelectedEdges ( [ edge ] )
305
336
}
306
337
}
307
338
308
339
hooks . emit . click ( data )
309
340
}
310
341
311
342
function onEdgeContextMenu ( event : MouseEvent ) {
312
- hooks . emit . contextMenu ( { event, edge : edge . value } )
343
+ hooks . emit . contextMenu ( { event, edge } )
313
344
}
314
345
315
346
function onDoubleClick ( event : MouseEvent ) {
316
- hooks . emit . doubleClick ( { event, edge : edge . value } )
347
+ hooks . emit . doubleClick ( { event, edge } )
317
348
}
318
349
319
350
function onEdgeMouseEnter ( event : MouseEvent ) {
320
- hooks . emit . mouseEnter ( { event, edge : edge . value } )
351
+ hooks . emit . mouseEnter ( { event, edge } )
321
352
}
322
353
323
354
function onEdgeMouseMove ( event : MouseEvent ) {
324
- hooks . emit . mouseMove ( { event, edge : edge . value } )
355
+ hooks . emit . mouseMove ( { event, edge } )
325
356
}
326
357
327
358
function onEdgeMouseLeave ( event : MouseEvent ) {
328
- hooks . emit . mouseLeave ( { event, edge : edge . value } )
359
+ hooks . emit . mouseLeave ( { event, edge } )
329
360
}
330
361
331
362
function onEdgeUpdaterSourceMouseDown ( event : MouseEvent ) {
@@ -337,7 +368,7 @@ const EdgeWrapper = defineComponent({
337
368
}
338
369
339
370
function onKeyDown ( event : KeyboardEvent ) {
340
- if ( ! disableKeyboardA11y . value && elementSelectionKeys . includes ( event . key ) && props . selectable ) {
371
+ if ( ! disableKeyboardA11y . value && elementSelectionKeys . includes ( event . key ) && isSelectable . value ) {
341
372
const unselect = event . key === 'Escape'
342
373
343
374
if ( unselect ) {
0 commit comments