feat(vue-flow): add autoConnect option

# What's changed?

* auto-connect allows to easily enable the default add edge change handler (shown in the examples)
* allow auto-connect to be a function that returns false when connection is cancelled or partial edge when it should be created
This commit is contained in:
bcakmakoglu
2022-06-16 23:00:31 +02:00
committed by Braks
parent 5a563e45b6
commit e047be6854
6 changed files with 62 additions and 7 deletions
@@ -36,6 +36,7 @@ const props = withDefaults(defineProps<FlowProps>(), {
fitViewOnInit: undefined,
connectOnClick: undefined,
connectionLineStyle: undefined,
autoConnect: undefined,
})
const emit = defineEmits<{
@@ -1,6 +1,7 @@
import type { Ref, ToRefs } from 'vue'
import type { WatchPausableReturn } from '@vueuse/core'
import type { FlowProps, GraphEdge, GraphNode, VueFlowStore } from '~/types'
import { isFunction } from '@vueuse/core'
import type { Connection, FlowProps, GraphEdge, GraphNode, VueFlowStore } from '~/types'
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
export default (models: ToRefs<Pick<FlowProps, 'nodes' | 'edges' | 'modelValue'>>, props: FlowProps, store: VueFlowStore) => {
@@ -171,8 +172,45 @@ export default (models: ToRefs<Pick<FlowProps, 'nodes' | 'edges' | 'modelValue'>
})
}
const watchAutoConnect = () => {
scope.run(() => {
watch(
() => props.autoConnect,
() => {
if (isDef(props.autoConnect)) {
store.autoConnect.value = props.autoConnect
}
},
{ immediate: isDef(props.autoConnect) },
)
watch(
store.autoConnect,
() => {
const autoConnector = async (params: Connection) => {
let connect: boolean | Connection = true
if (isFunction(props.autoConnect)) {
connect = await props.autoConnect(params)
}
if (connect) {
store.addEdges([params])
}
}
if (store.autoConnect) {
store.onConnect(autoConnector)
} else {
store.hooks.value.connect.off(autoConnector)
}
},
{ immediate: true },
)
})
}
const watchRest = () => {
const skip = ['id', 'modelValue', 'edges', 'nodes', 'maxZoom', 'minZoom', 'applyDefault']
const skip = ['id', 'modelValue', 'edges', 'nodes', 'maxZoom', 'minZoom', 'applyDefault', 'autoConnect']
Object.keys(props).forEach((prop) => {
if (!skip.includes(prop)) {
const model = props[prop as keyof typeof props]
@@ -193,9 +231,16 @@ export default (models: ToRefs<Pick<FlowProps, 'nodes' | 'edges' | 'modelValue'>
})
}
;[watchModelValue, watchNodesValue, watchEdgesValue, watchMinZoom, watchMaxZoom, watchApplyDefault, watchRest].forEach(
(watch) => watch(),
)
;[
watchModelValue,
watchNodesValue,
watchEdgesValue,
watchMinZoom,
watchMaxZoom,
watchApplyDefault,
watchAutoConnect,
watchRest,
].forEach((watch) => watch())
})
return () => scope.stop()
+1
View File
@@ -101,6 +101,7 @@ const defaultState = (): State => ({
hooks: createHooks(),
applyDefault: true,
autoConnect: false,
fitViewOnInit: false,
noDragClassName: 'nodrag',
@@ -2,6 +2,7 @@ import type { CSSProperties } from 'vue'
import type { Position } from './flow'
import type { GraphNode } from './node'
import type { HandleElement, HandleType } from './handle'
import type { Edge } from './edge'
/** Connection line types (same as default edge types */
export enum ConnectionLineType {
@@ -23,6 +24,10 @@ export interface Connection {
targetHandle: string | null
}
export type Connector = (
params: Connection,
) => Promise<(Connection & Partial<Edge>) | false> | ((Connection & Partial<Edge>) | false)
/** The source nodes params when connection is initiated */
export interface OnConnectStartParams {
/** Source node id */
+3 -1
View File
@@ -1,7 +1,7 @@
import type { CSSProperties } from 'vue'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node'
import type { ConnectionLineType, ConnectionMode } from './connection'
import type { ConnectionLineType, ConnectionMode, Connector } from './connection'
import type { KeyCode, PanOnScrollMode } from './zoom'
import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
@@ -122,6 +122,8 @@ export interface FlowProps {
connectOnClick?: boolean
/** apply default change handlers for position, dimensions, adding/removing nodes. set this to false if you want to apply the changes manually */
applyDefault?: boolean
/** automatically create an edge when connection is triggered */
autoConnect?: boolean | Connector
noDragClassName?: string
noWheelClassName?: string
noPanClassName?: string
+2 -1
View File
@@ -1,7 +1,7 @@
import type { CSSProperties, ComputedRef, ToRefs } from 'vue'
import type { Dimensions, ElementData, Elements, FlowElements, FlowExportObject, FlowOptions, SnapGrid, XYPosition } from './flow'
import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
import type { Connection, ConnectionLineType, ConnectionMode } from './connection'
import type { Connection, ConnectionLineType, ConnectionMode, Connector } from './connection'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node'
import type { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode, Viewport, ViewportFunctions } from './zoom'
@@ -88,6 +88,7 @@ export interface State extends Omit<FlowOptions, 'id' | 'modelValue'> {
initialized: boolean
applyDefault: boolean
autoConnect: boolean | Connector
fitViewOnInit?: boolean