feat(core): add onError hook
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Vendored
+3
-1
@@ -14,12 +14,13 @@ declare global {
|
|||||||
const EdgeId: typeof import('./context/index')['EdgeId']
|
const EdgeId: typeof import('./context/index')['EdgeId']
|
||||||
const EdgeRef: typeof import('./context/index')['EdgeRef']
|
const EdgeRef: typeof import('./context/index')['EdgeRef']
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const ErrorCode: typeof import('./utils/errors')['ErrorCode']
|
||||||
const NodeId: typeof import('./context/index')['NodeId']
|
const NodeId: typeof import('./context/index')['NodeId']
|
||||||
const NodeRef: typeof import('./context/index')['NodeRef']
|
const NodeRef: typeof import('./context/index')['NodeRef']
|
||||||
const Slots: typeof import('./context/index')['Slots']
|
const Slots: typeof import('./context/index')['Slots']
|
||||||
const Storage: typeof import('./composables/useVueFlow')['Storage']
|
const Storage: typeof import('./composables/useVueFlow')['Storage']
|
||||||
const VueFlow: typeof import('./context/index')['VueFlow']
|
const VueFlow: typeof import('./context/index')['VueFlow']
|
||||||
const VueFlowError: typeof import('./utils/log')['VueFlowError']
|
const VueFlowError: typeof import('./utils/errors')['VueFlowError']
|
||||||
const addEdge: typeof import('./utils/graph')['addEdge']
|
const addEdge: typeof import('./utils/graph')['addEdge']
|
||||||
const addEdgeToStore: typeof import('./utils/store')['addEdgeToStore']
|
const addEdgeToStore: typeof import('./utils/store')['addEdgeToStore']
|
||||||
const applyChanges: typeof import('./utils/changes')['applyChanges']
|
const applyChanges: typeof import('./utils/changes')['applyChanges']
|
||||||
@@ -44,6 +45,7 @@ declare global {
|
|||||||
const createAdditionChange: typeof import('./utils/changes')['createAdditionChange']
|
const createAdditionChange: typeof import('./utils/changes')['createAdditionChange']
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue')['createApp']
|
||||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
||||||
|
const createExtendedEventHook: typeof import('./utils/createExtendedEventHook')['createExtendedEventHook']
|
||||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||||
const createGraphNodes: typeof import('./utils/store')['createGraphNodes']
|
const createGraphNodes: typeof import('./utils/store')['createGraphNodes']
|
||||||
const createHooks: typeof import('./store/hooks')['createHooks']
|
const createHooks: typeof import('./store/hooks')['createHooks']
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ const NodeWrapper = defineComponent({
|
|||||||
nextPos.y = snapGrid[1] * Math.round(nextPos.y / snapGrid[1])
|
nextPos.y = snapGrid[1] * Math.round(nextPos.y / snapGrid[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
const { computedPosition, position } = calcNextPosition(node, nextPos, nodeExtent, parentNode)
|
const { computedPosition, position } = calcNextPosition(node, nextPos, emits.error, nodeExtent, parentNode)
|
||||||
|
|
||||||
// only overwrite positions if there are changes when clamping
|
// only overwrite positions if there are changes when clamping
|
||||||
if (node.computedPosition.x !== computedPosition.x || node.computedPosition.y !== computedPosition.y) {
|
if (node.computedPosition.x !== computedPosition.x || node.computedPosition.y !== computedPosition.y) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ function useDrag(params: UseDragParams) {
|
|||||||
removeSelectedElements,
|
removeSelectedElements,
|
||||||
addSelectedNodes,
|
addSelectedNodes,
|
||||||
updateNodePositions,
|
updateNodePositions,
|
||||||
|
emits,
|
||||||
} = $(useVueFlow())
|
} = $(useVueFlow())
|
||||||
|
|
||||||
const { onStart, onDrag, onStop, el, disabled, id, selectable } = $(params)
|
const { onStart, onDrag, onStop, el, disabled, id, selectable } = $(params)
|
||||||
@@ -83,6 +84,7 @@ function useDrag(params: UseDragParams) {
|
|||||||
const { computedPosition } = calcNextPosition(
|
const { computedPosition } = calcNextPosition(
|
||||||
n,
|
n,
|
||||||
nextPosition,
|
nextPosition,
|
||||||
|
emits.error,
|
||||||
nodeExtent,
|
nodeExtent,
|
||||||
n.parentNode ? findNode(n.parentNode) : undefined,
|
n.parentNode ? findNode(n.parentNode) : undefined,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { CustomEvent, ElementData } from '~/types'
|
import type { CustomEvent, ElementData } from '~/types'
|
||||||
|
import { VueFlowError } from '~/utils/errors'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access an edge
|
* Access an edge
|
||||||
@@ -11,12 +12,12 @@ export default function useEdge<Data = ElementData, CustomEvents extends Record<
|
|||||||
const edgeId = id ?? inject(EdgeId, '')
|
const edgeId = id ?? inject(EdgeId, '')
|
||||||
const edgeEl = inject(EdgeRef, null)
|
const edgeEl = inject(EdgeRef, null)
|
||||||
|
|
||||||
const { findEdge } = useVueFlow()
|
const { findEdge, emits } = useVueFlow()
|
||||||
|
|
||||||
const edge = findEdge<Data, CustomEvents>(edgeId)
|
const edge = findEdge<Data, CustomEvents>(edgeId)
|
||||||
|
|
||||||
if (!edge) {
|
if (!edge) {
|
||||||
throw new VueFlowError(`Edge with id ${edgeId} not found!`, 'useEdge')
|
emits.error(new VueFlowError(ErrorCode.EDGE_NOT_FOUND, edgeId))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import type { EdgeEventsEmit, EdgeEventsOn, GraphEdge, VueFlowStore } from '~/types'
|
import type { EdgeEventsEmit, EdgeEventsOn, GraphEdge, VueFlowStore } from '~/types'
|
||||||
|
|
||||||
const createEdgeHooks = () => ({
|
const createEdgeHooks = () => ({
|
||||||
doubleClick: createEventHook(),
|
doubleClick: createExtendedEventHook(),
|
||||||
click: createEventHook(),
|
click: createExtendedEventHook(),
|
||||||
mouseEnter: createEventHook(),
|
mouseEnter: createExtendedEventHook(),
|
||||||
mouseMove: createEventHook(),
|
mouseMove: createExtendedEventHook(),
|
||||||
mouseLeave: createEventHook(),
|
mouseLeave: createExtendedEventHook(),
|
||||||
contextMenu: createEventHook(),
|
contextMenu: createExtendedEventHook(),
|
||||||
updateStart: createEventHook(),
|
updateStart: createExtendedEventHook(),
|
||||||
update: createEventHook(),
|
update: createExtendedEventHook(),
|
||||||
updateEnd: createEventHook(),
|
updateEnd: createExtendedEventHook(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function useEdgeHooks(edge: GraphEdge, emits: VueFlowStore['emits']): { emit: EdgeEventsEmit; on: EdgeEventsOn } {
|
export default function useEdgeHooks(edge: GraphEdge, emits: VueFlowStore['emits']): { emit: EdgeEventsEmit; on: EdgeEventsOn } {
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ export default function useNode<Data = ElementData, CustomEvents extends Record<
|
|||||||
const nodeId = id ?? inject(NodeId, '')
|
const nodeId = id ?? inject(NodeId, '')
|
||||||
const nodeEl = inject(NodeRef, null)
|
const nodeEl = inject(NodeRef, null)
|
||||||
|
|
||||||
const { findNode, getEdges } = useVueFlow()
|
const { findNode, getEdges, emits } = useVueFlow()
|
||||||
|
|
||||||
const node = findNode<Data, CustomEvents>(nodeId)
|
const node = findNode<Data, CustomEvents>(nodeId)
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
throw new VueFlowError(`Node with id ${nodeId} not found!`, 'useNode')
|
emits.error(new VueFlowError(ErrorCode.NODE_NOT_FOUND, nodeId))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
nodeEl,
|
nodeEl,
|
||||||
node,
|
node,
|
||||||
parentNode: computed(() => (node.parentNode ? findNode(node.parentNode) : undefined)),
|
parentNode: computed(() => (node!.parentNode ? findNode(node!.parentNode) : undefined)),
|
||||||
connectedEdges: computed(() => getConnectedEdges([node], getEdges.value)),
|
connectedEdges: computed(() => getConnectedEdges([node!], getEdges.value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import type { GraphNode, NodeEventsEmit, NodeEventsOn, VueFlowStore } from '~/types'
|
import type { GraphNode, NodeEventsEmit, NodeEventsOn, VueFlowStore } from '~/types'
|
||||||
|
|
||||||
const createNodeHooks = () => ({
|
const createNodeHooks = () => ({
|
||||||
doubleClick: createEventHook(),
|
doubleClick: createExtendedEventHook(),
|
||||||
click: createEventHook(),
|
click: createExtendedEventHook(),
|
||||||
mouseEnter: createEventHook(),
|
mouseEnter: createExtendedEventHook(),
|
||||||
mouseMove: createEventHook(),
|
mouseMove: createExtendedEventHook(),
|
||||||
mouseLeave: createEventHook(),
|
mouseLeave: createExtendedEventHook(),
|
||||||
contextMenu: createEventHook(),
|
contextMenu: createExtendedEventHook(),
|
||||||
dragStart: createEventHook(),
|
dragStart: createExtendedEventHook(),
|
||||||
drag: createEventHook(),
|
drag: createExtendedEventHook(),
|
||||||
dragStop: createEventHook(),
|
dragStop: createExtendedEventHook(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function useNodeHooks(node: GraphNode, emits: VueFlowStore['emits']): { emit: NodeEventsEmit; on: NodeEventsOn } {
|
export default function useNodeHooks(node: GraphNode, emits: VueFlowStore['emits']): { emit: NodeEventsEmit; on: NodeEventsOn } {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { NodeDragItem, XYPosition } from '~/types'
|
import type { NodeDragItem, XYPosition } from '~/types'
|
||||||
|
|
||||||
function useUpdateNodePositions() {
|
function useUpdateNodePositions() {
|
||||||
const { getSelectedNodes, nodeExtent, updateNodePositions, findNode, snapGrid, snapToGrid, nodesDraggable } = useVueFlow()
|
const { getSelectedNodes, nodeExtent, updateNodePositions, findNode, snapGrid, snapToGrid, nodesDraggable, emits } =
|
||||||
|
useVueFlow()
|
||||||
|
|
||||||
return (positionDiff: XYPosition, isShiftPressed = false) => {
|
return (positionDiff: XYPosition, isShiftPressed = false) => {
|
||||||
// by default a node moves 5px on each key press, or 20px if shift is pressed
|
// by default a node moves 5px on each key press, or 20px if shift is pressed
|
||||||
@@ -21,6 +22,7 @@ function useUpdateNodePositions() {
|
|||||||
const { computedPosition } = calcNextPosition(
|
const { computedPosition } = calcNextPosition(
|
||||||
n,
|
n,
|
||||||
nextPosition,
|
nextPosition,
|
||||||
|
emits.error,
|
||||||
nodeExtent.value,
|
nodeExtent.value,
|
||||||
n.parentNode ? findNode(n.parentNode) : undefined,
|
n.parentNode ? findNode(n.parentNode) : undefined,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -123,11 +123,6 @@ export default (options?: FlowProps): VueFlowStore => {
|
|||||||
if (options) vueFlow.setState(options)
|
if (options) vueFlow.setState(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Vue flow wasn't able to find any store instance - we can't proceed
|
|
||||||
*/
|
|
||||||
if (!vueFlow) throw new VueFlowError('Store instance not found.', 'useVueFlow')
|
|
||||||
|
|
||||||
// always provide a fresh instance into context on call
|
// always provide a fresh instance into context on call
|
||||||
if (scope) {
|
if (scope) {
|
||||||
provide(VueFlow, vueFlow)
|
provide(VueFlow, vueFlow)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const {
|
|||||||
getEdgeTypes,
|
getEdgeTypes,
|
||||||
elevateEdgesOnSelect,
|
elevateEdgesOnSelect,
|
||||||
dimensions,
|
dimensions,
|
||||||
|
emits,
|
||||||
} = $(useVueFlow())
|
} = $(useVueFlow())
|
||||||
|
|
||||||
const sourceNode = controlledComputed(
|
const sourceNode = controlledComputed(
|
||||||
@@ -75,7 +76,7 @@ function getType(type?: string, template?: GraphEdge['template']) {
|
|||||||
|
|
||||||
const slot = slots?.[`edge-${name}`]
|
const slot = slots?.[`edge-${name}`]
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
warn(`Edge type "${type}" not found and no edge-slot detected. Using fallback type "default".`)
|
emits.error(new VueFlowError(ErrorCode.EDGE_TYPE_MISSING, edgeType))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function getType(type?: string, template?: GraphNode['template']) {
|
|||||||
|
|
||||||
const slot = slots?.[`node-${name}`]
|
const slot = slots?.[`node-${name}`]
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
warn(`Node type "${type}" not found and no node-slot detected. Using fallback type "default".`)
|
emits.error(new VueFlowError(ErrorCode.NODE_TYPE_MISSING, nodeType))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -287,7 +287,9 @@ function setDimensions() {
|
|||||||
|
|
||||||
const { width, height } = getDimensions(viewportEl.value)
|
const { width, height } = getDimensions(viewportEl.value)
|
||||||
|
|
||||||
if (width === 0 || height === 0) warn('The Vue Flow parent container needs a width and a height to render the graph.')
|
if (width === 0 || height === 0) {
|
||||||
|
emits.error(new VueFlowError(ErrorCode.MISSING_VIEWPORT_DIMENSIONS))
|
||||||
|
}
|
||||||
|
|
||||||
dimensions.width = width || 500
|
dimensions.width = width || 500
|
||||||
dimensions.height = height || 500
|
dimensions.height = height || 500
|
||||||
|
|||||||
@@ -71,6 +71,6 @@ export { default as useEdge } from './composables/useEdge'
|
|||||||
|
|
||||||
export { useGetPointerPosition } from './composables/useGetPointerPosition'
|
export { useGetPointerPosition } from './composables/useGetPointerPosition'
|
||||||
|
|
||||||
export { VueFlowError } from './utils/log'
|
export { VueFlowError, ErrorCode } from './utils/errors'
|
||||||
|
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
|
|
||||||
if (!state.initialized && !nextNodes.length) return
|
if (!state.initialized && !nextNodes.length) return
|
||||||
|
|
||||||
state.nodes = createGraphNodes(nextNodes, findNode, state.nodes)
|
state.nodes = createGraphNodes(nextNodes, state.nodes, findNode, state.hooks.error.trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setEdges: Actions['setEdges'] = (edges) => {
|
const setEdges: Actions['setEdges'] = (edges) => {
|
||||||
@@ -315,9 +315,21 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
|
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
|
||||||
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
||||||
|
|
||||||
if (missingSource) warn(`Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
if (missingSource && missingTarget) {
|
||||||
if (missingTarget) warn(`Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_TARGET_MISSING, edge.id, edge.source, edge.target))
|
||||||
if (missingSource || missingTarget) return res
|
} else {
|
||||||
|
if (missingSource) {
|
||||||
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_MISSING, edge.id, edge.source))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingTarget) {
|
||||||
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_TARGET_MISSING, edge.id, edge.target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingSource || missingTarget) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
const storedEdge = getters.getEdge.value(edge.id)
|
const storedEdge = getters.getEdge.value(edge.id)
|
||||||
|
|
||||||
@@ -343,7 +355,7 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
const addNodes: Actions['addNodes'] = (nodes) => {
|
const addNodes: Actions['addNodes'] = (nodes) => {
|
||||||
const nextNodes = nodes instanceof Function ? nodes(state.nodes) : nodes
|
const nextNodes = nodes instanceof Function ? nodes(state.nodes) : nodes
|
||||||
|
|
||||||
const graphNodes = createGraphNodes(nextNodes, findNode, state.nodes)
|
const graphNodes = createGraphNodes(nextNodes, state.nodes, findNode, state.hooks.error.trigger)
|
||||||
|
|
||||||
const changes = graphNodes.map(createAdditionChange)
|
const changes = graphNodes.map(createAdditionChange)
|
||||||
|
|
||||||
@@ -370,6 +382,7 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
...state.defaultEdgeOptions,
|
...state.defaultEdgeOptions,
|
||||||
},
|
},
|
||||||
state.edges,
|
state.edges,
|
||||||
|
state.hooks.error.trigger,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (edge) {
|
if (edge) {
|
||||||
@@ -379,9 +392,21 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
|
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
|
||||||
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
||||||
|
|
||||||
if (missingSource) warn(`Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
if (missingSource && missingTarget) {
|
||||||
if (missingTarget) warn(`Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_TARGET_MISSING, edge.id, edge.source, edge.target))
|
||||||
if (missingTarget || missingSource) return acc
|
} else {
|
||||||
|
if (missingSource) {
|
||||||
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_MISSING, edge.id, edge.source))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingTarget) {
|
||||||
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_TARGET_MISSING, edge.id, edge.target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingSource || missingTarget) {
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
acc.push(
|
acc.push(
|
||||||
createAdditionChange<GraphEdge>({
|
createAdditionChange<GraphEdge>({
|
||||||
@@ -445,7 +470,7 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection, shouldReplaceId = true) =>
|
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection, shouldReplaceId = true) =>
|
||||||
updateEdgeAction(oldEdge, newConnection, state.edges, findEdge, shouldReplaceId)
|
updateEdgeAction(oldEdge, newConnection, state.edges, findEdge, shouldReplaceId, state.hooks.error.trigger)
|
||||||
|
|
||||||
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes)
|
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes)
|
||||||
|
|
||||||
@@ -468,8 +493,6 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
state.connectionPosition = position
|
state.connectionPosition = position
|
||||||
state.connectionStartHandle.result = result
|
state.connectionStartHandle.result = result
|
||||||
state.connectionStatus = status
|
state.connectionStatus = status
|
||||||
} else {
|
|
||||||
warn('Cannot update connection as it has not been started')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function useGetters(state: State): ComputedGetters {
|
|||||||
if (!source || !target) {
|
if (!source || !target) {
|
||||||
state.edges = state.edges.filter((edge) => edge.id !== e.id)
|
state.edges = state.edges.filter((edge) => edge.id !== e.id)
|
||||||
|
|
||||||
warn(`Orphaned edge ${e.id} removed.`)
|
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_ORPHANED, e.id))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +1,65 @@
|
|||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import type { Emits, FlowHooks } from '~/types'
|
import type { FlowHooks } from '~/types'
|
||||||
|
|
||||||
// flow event hooks
|
// flow event hooks
|
||||||
export const createHooks = (): FlowHooks => ({
|
export const createHooks = (): FlowHooks => ({
|
||||||
edgesChange: createEventHook(),
|
edgesChange: createExtendedEventHook(),
|
||||||
nodesChange: createEventHook(),
|
nodesChange: createExtendedEventHook(),
|
||||||
nodeDoubleClick: createEventHook(),
|
nodeDoubleClick: createExtendedEventHook(),
|
||||||
nodeClick: createEventHook(),
|
nodeClick: createExtendedEventHook(),
|
||||||
nodeMouseEnter: createEventHook(),
|
nodeMouseEnter: createExtendedEventHook(),
|
||||||
nodeMouseMove: createEventHook(),
|
nodeMouseMove: createExtendedEventHook(),
|
||||||
nodeMouseLeave: createEventHook(),
|
nodeMouseLeave: createExtendedEventHook(),
|
||||||
nodeContextMenu: createEventHook(),
|
nodeContextMenu: createExtendedEventHook(),
|
||||||
nodeDragStart: createEventHook(),
|
nodeDragStart: createExtendedEventHook(),
|
||||||
nodeDrag: createEventHook(),
|
nodeDrag: createExtendedEventHook(),
|
||||||
nodeDragStop: createEventHook(),
|
nodeDragStop: createExtendedEventHook(),
|
||||||
nodesInitialized: createEventHook(),
|
nodesInitialized: createExtendedEventHook(),
|
||||||
miniMapNodeClick: createEventHook(),
|
miniMapNodeClick: createExtendedEventHook(),
|
||||||
miniMapNodeDoubleClick: createEventHook(),
|
miniMapNodeDoubleClick: createExtendedEventHook(),
|
||||||
miniMapNodeMouseEnter: createEventHook(),
|
miniMapNodeMouseEnter: createExtendedEventHook(),
|
||||||
miniMapNodeMouseMove: createEventHook(),
|
miniMapNodeMouseMove: createExtendedEventHook(),
|
||||||
miniMapNodeMouseLeave: createEventHook(),
|
miniMapNodeMouseLeave: createExtendedEventHook(),
|
||||||
connect: createEventHook(),
|
connect: createExtendedEventHook(),
|
||||||
connectStart: createEventHook(),
|
connectStart: createExtendedEventHook(),
|
||||||
connectEnd: createEventHook(),
|
connectEnd: createExtendedEventHook(),
|
||||||
paneReady: createEventHook(),
|
paneReady: createExtendedEventHook(),
|
||||||
move: createEventHook(),
|
move: createExtendedEventHook(),
|
||||||
moveStart: createEventHook(),
|
moveStart: createExtendedEventHook(),
|
||||||
moveEnd: createEventHook(),
|
moveEnd: createExtendedEventHook(),
|
||||||
selectionDragStart: createEventHook(),
|
selectionDragStart: createExtendedEventHook(),
|
||||||
selectionDrag: createEventHook(),
|
selectionDrag: createExtendedEventHook(),
|
||||||
selectionDragStop: createEventHook(),
|
selectionDragStop: createExtendedEventHook(),
|
||||||
selectionContextMenu: createEventHook(),
|
selectionContextMenu: createExtendedEventHook(),
|
||||||
selectionStart: createEventHook(),
|
selectionStart: createExtendedEventHook(),
|
||||||
selectionEnd: createEventHook(),
|
selectionEnd: createExtendedEventHook(),
|
||||||
viewportChangeStart: createEventHook(),
|
viewportChangeStart: createExtendedEventHook(),
|
||||||
viewportChange: createEventHook(),
|
viewportChange: createExtendedEventHook(),
|
||||||
viewportChangeEnd: createEventHook(),
|
viewportChangeEnd: createExtendedEventHook(),
|
||||||
paneScroll: createEventHook(),
|
paneScroll: createExtendedEventHook(),
|
||||||
paneClick: createEventHook(),
|
paneClick: createExtendedEventHook(),
|
||||||
paneContextMenu: createEventHook(),
|
paneContextMenu: createExtendedEventHook(),
|
||||||
paneMouseEnter: createEventHook(),
|
paneMouseEnter: createExtendedEventHook(),
|
||||||
paneMouseMove: createEventHook(),
|
paneMouseMove: createExtendedEventHook(),
|
||||||
paneMouseLeave: createEventHook(),
|
paneMouseLeave: createExtendedEventHook(),
|
||||||
edgeContextMenu: createEventHook(),
|
edgeContextMenu: createExtendedEventHook(),
|
||||||
edgeMouseEnter: createEventHook(),
|
edgeMouseEnter: createExtendedEventHook(),
|
||||||
edgeMouseMove: createEventHook(),
|
edgeMouseMove: createExtendedEventHook(),
|
||||||
edgeMouseLeave: createEventHook(),
|
edgeMouseLeave: createExtendedEventHook(),
|
||||||
edgeDoubleClick: createEventHook(),
|
edgeDoubleClick: createExtendedEventHook(),
|
||||||
edgeClick: createEventHook(),
|
edgeClick: createExtendedEventHook(),
|
||||||
edgeUpdateStart: createEventHook(),
|
edgeUpdateStart: createExtendedEventHook(),
|
||||||
edgeUpdate: createEventHook(),
|
edgeUpdate: createExtendedEventHook(),
|
||||||
edgeUpdateEnd: createEventHook(),
|
edgeUpdateEnd: createExtendedEventHook(),
|
||||||
updateNodeInternals: createEventHook(),
|
updateNodeInternals: createExtendedEventHook(),
|
||||||
|
error: createExtendedEventHook((err) => warn(err.message)),
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useHooks(emit: Emits, hooks: Ref<FlowHooks>) {
|
export function useHooks(emit: (...args: any[]) => void, hooks: Ref<FlowHooks>) {
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
for (const [key, value] of Object.entries(hooks.value)) {
|
for (const [key, value] of Object.entries(hooks.value)) {
|
||||||
const listener = (data: any) => {
|
const listener = (data: any) => {
|
||||||
emit(key as Emits extends (event: infer Event) => void ? Event : never, data)
|
emit(key, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
value.on(listener)
|
value.on(listener)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { Connection, OnConnectStartParams } from './connection'
|
|||||||
import type { ViewportTransform } from './zoom'
|
import type { ViewportTransform } from './zoom'
|
||||||
import type { EdgeChange, NodeChange } from './changes'
|
import type { EdgeChange, NodeChange } from './changes'
|
||||||
import type { VueFlowStore } from './store'
|
import type { VueFlowStore } from './store'
|
||||||
import type { FlowElements } from './flow'
|
import type { VueFlowError } from '~/utils/errors'
|
||||||
|
|
||||||
export type MouseTouchEvent = MouseEvent | TouchEvent
|
export type MouseTouchEvent = MouseEvent | TouchEvent
|
||||||
|
|
||||||
@@ -86,68 +86,7 @@ export interface FlowEvents {
|
|||||||
edgeUpdateStart: EdgeMouseEvent
|
edgeUpdateStart: EdgeMouseEvent
|
||||||
edgeUpdate: EdgeUpdateEvent
|
edgeUpdate: EdgeUpdateEvent
|
||||||
edgeUpdateEnd: EdgeMouseEvent
|
edgeUpdateEnd: EdgeMouseEvent
|
||||||
}
|
error: VueFlowError
|
||||||
|
|
||||||
export interface Emits {
|
|
||||||
(event: 'nodesChange', changes: NodeChange[]): void
|
|
||||||
(event: 'edgesChange', changes: EdgeChange[]): void
|
|
||||||
(event: 'nodeDoubleClick', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeClick', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeMouseEnter', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeMouseMove', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeMouseLeave', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeContextMenu', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'nodeDragStart', nodeDragEvent: NodeDragEvent): void
|
|
||||||
(event: 'nodeDrag', nodeDragEvent: NodeDragEvent): void
|
|
||||||
(event: 'nodeDragStop', nodeDragEvent: NodeDragEvent): void
|
|
||||||
(event: 'nodesInitialized'): void
|
|
||||||
(event: 'miniMapNodeClick', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'miniMapNodeDoubleClick', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'miniMapNodeMouseEnter', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'miniMapNodeMouseMove', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'miniMapNodeMouseLeave', nodeMouseEvent: NodeMouseEvent): void
|
|
||||||
(event: 'connect', connectionEvent: Connection): void
|
|
||||||
(
|
|
||||||
event: 'connectStart',
|
|
||||||
connectionEvent: {
|
|
||||||
event?: MouseEvent
|
|
||||||
} & OnConnectStartParams,
|
|
||||||
): void
|
|
||||||
(event: 'connectEnd', connectionEvent?: MouseEvent): void
|
|
||||||
(event: 'moveStart', moveEvent: { event: D3ZoomEvent<HTMLDivElement, any>; flowTransform: ViewportTransform }): void
|
|
||||||
(event: 'move', moveEvent: { event: D3ZoomEvent<HTMLDivElement, any>; flowTransform: ViewportTransform }): void
|
|
||||||
(event: 'moveEnd', moveEvent: { event: D3ZoomEvent<HTMLDivElement, any>; flowTransform: ViewportTransform }): void
|
|
||||||
(event: 'selectionDragStart', selectionEvent: NodeDragEvent): void
|
|
||||||
(event: 'selectionDrag', selectionEvent: NodeDragEvent): void
|
|
||||||
(event: 'selectionDragStop', selectionEvent: NodeDragEvent): void
|
|
||||||
(event: 'selectionContextMenu', selectionEvent: { event: MouseEvent; nodes: GraphNode[] }): void
|
|
||||||
(event: 'selectionStart', selectionEvent: MouseEvent): void
|
|
||||||
(event: 'selectionEnd', selectionEvent: MouseEvent): void
|
|
||||||
(event: 'viewportChangeStart', viewport: ViewportTransform): void
|
|
||||||
(event: 'viewportChange', viewport: ViewportTransform): void
|
|
||||||
(event: 'viewportChangeEnd', viewport: ViewportTransform): void
|
|
||||||
(event: 'paneReady', paneEvent: VueFlowStore): void
|
|
||||||
(event: 'paneScroll', paneEvent: WheelEvent | undefined): void
|
|
||||||
(event: 'paneClick', paneEvent: MouseEvent): void
|
|
||||||
(event: 'paneContextMenu', paneEvent: MouseEvent): void
|
|
||||||
(event: 'paneMouseEnter', paneEvent: MouseEvent): void
|
|
||||||
(event: 'paneMouseMove', paneEvent: MouseEvent): void
|
|
||||||
(event: 'paneMouseLeave', paneEvent: MouseEvent): void
|
|
||||||
(event: 'edgeContextMenu', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeMouseEnter', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeMouseMove', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeMouseLeave', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeDoubleClick', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeClick', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeUpdateStart', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'edgeUpdate', edgeUpdateEvent: EdgeUpdateEvent): void
|
|
||||||
(event: 'edgeUpdateEnd', edgeMouseEvent: EdgeMouseEvent): void
|
|
||||||
(event: 'updateNodeInternals'): void
|
|
||||||
|
|
||||||
/** v-model event definitions */
|
|
||||||
(event: 'update:modelValue', value: FlowElements): void
|
|
||||||
(event: 'update:nodes', value: GraphNode[]): void
|
|
||||||
(event: 'update:edges', value: GraphEdge[]): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FlowHooks = Readonly<{
|
export type FlowHooks = Readonly<{
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import type { EventHook } from '@vueuse/core'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source code taken from https://github.com/vueuse/vueuse/blob/main/packages/shared/createEventHook/index.ts
|
||||||
|
*
|
||||||
|
* Modified to be able to check if there are any event listeners
|
||||||
|
*/
|
||||||
|
export interface EventHookExtended<T> extends EventHook<T> {
|
||||||
|
fns: Ref<Set<(param: T) => void>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createExtendedEventHook<T = any>(defaultHandler: (param: T) => void = () => {}): EventHookExtended<T> {
|
||||||
|
const fns = ref(new Set<(param: T) => void>())
|
||||||
|
|
||||||
|
if (defaultHandler) {
|
||||||
|
fns.value.add(defaultHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
const off = (fn: (param: T) => void) => {
|
||||||
|
fns.value.delete(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
const on = (fn: (param: T) => void) => {
|
||||||
|
if (fns.value.has(defaultHandler)) {
|
||||||
|
fns.value.delete(defaultHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
fns.value.add(fn)
|
||||||
|
const offFn = () => off(fn)
|
||||||
|
|
||||||
|
tryOnScopeDispose(offFn)
|
||||||
|
|
||||||
|
return {
|
||||||
|
off: offFn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = (param: T) => {
|
||||||
|
return Promise.all(Array.from(fns.value).map((fn) => fn(param)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
on,
|
||||||
|
off,
|
||||||
|
trigger,
|
||||||
|
fns,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { isNumber } from '@vueuse/shared'
|
import { isNumber } from '@vueuse/shared'
|
||||||
import type { Actions, CoordinateExtent, ExtendedParentExtent, GraphNode, NodeDragItem, XYPosition } from '~/types'
|
import type { Actions, CoordinateExtent, ExtendedParentExtent, GraphNode, NodeDragItem, State, XYPosition } from '~/types'
|
||||||
|
|
||||||
export function hasSelector(target: Element, selector: string, node: Element): boolean {
|
export function hasSelector(target: Element, selector: string, node: Element): boolean {
|
||||||
let current = target
|
let current = target
|
||||||
@@ -97,7 +97,12 @@ function getParentExtent(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getExtent<T extends NodeDragItem | GraphNode>(item: T, extent?: CoordinateExtent, parent?: GraphNode) {
|
export function getExtent<T extends NodeDragItem | GraphNode>(
|
||||||
|
item: T,
|
||||||
|
onError: State['hooks']['error']['trigger'],
|
||||||
|
extent?: CoordinateExtent,
|
||||||
|
parent?: GraphNode,
|
||||||
|
) {
|
||||||
let currentExtent = item.extent || extent
|
let currentExtent = item.extent || extent
|
||||||
|
|
||||||
if (item.extent === 'parent' || (!Array.isArray(item.extent) && item.extent?.range === 'parent')) {
|
if (item.extent === 'parent' || (!Array.isArray(item.extent) && item.extent?.range === 'parent')) {
|
||||||
@@ -108,7 +113,7 @@ export function getExtent<T extends NodeDragItem | GraphNode>(item: T, extent?:
|
|||||||
currentExtent = parentExtent
|
currentExtent = parentExtent
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn('Only child nodes can use a parent extent.')
|
onError(new VueFlowError(ErrorCode.NODE_EXTENT_INVALID, item.id))
|
||||||
|
|
||||||
currentExtent = extent
|
currentExtent = extent
|
||||||
}
|
}
|
||||||
@@ -127,10 +132,11 @@ export function getExtent<T extends NodeDragItem | GraphNode>(item: T, extent?:
|
|||||||
export function calcNextPosition(
|
export function calcNextPosition(
|
||||||
node: GraphNode | NodeDragItem,
|
node: GraphNode | NodeDragItem,
|
||||||
nextPosition: XYPosition,
|
nextPosition: XYPosition,
|
||||||
|
onError: State['hooks']['error']['trigger'],
|
||||||
nodeExtent?: CoordinateExtent,
|
nodeExtent?: CoordinateExtent,
|
||||||
parentNode?: GraphNode,
|
parentNode?: GraphNode,
|
||||||
) {
|
) {
|
||||||
const extent = getExtent(node, nodeExtent, parentNode)
|
const extent = getExtent(node, onError, nodeExtent, parentNode)
|
||||||
|
|
||||||
const clampedPos = clampPosition(nextPosition, extent)
|
const clampedPos = clampPosition(nextPosition, extent)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
export enum ErrorCode {
|
||||||
|
MISSING_VIEWPORT_DIMENSIONS = 'MISSING_VIEWPORT_DIMENSIONS',
|
||||||
|
NODE_NOT_FOUND = 'NODE_NOT_FOUND',
|
||||||
|
NODE_MISSING_PARENT = 'NODE_MISSING_PARENT',
|
||||||
|
NODE_TYPE_MISSING = 'NODE_TYPE_MISSING',
|
||||||
|
NODE_EXTENT_INVALID = 'NODE_EXTENT_INVALID',
|
||||||
|
EDGE_INVALID = 'EDGE_INVALID',
|
||||||
|
EDGE_NOT_FOUND = 'EDGE_NOT_FOUND',
|
||||||
|
EDGE_SOURCE_MISSING = 'EDGE_SOURCE_MISSING',
|
||||||
|
EDGE_TARGET_MISSING = 'EDGE_TARGET_MISSING',
|
||||||
|
EDGE_TYPE_MISSING = 'EDGE_TYPE_MISSING',
|
||||||
|
EDGE_SOURCE_TARGET_SAME = 'EDGE_SOURCE_TARGET_SAME',
|
||||||
|
EDGE_SOURCE_TARGET_MISSING = 'EDGE_SOURCE_TARGET_MISSING',
|
||||||
|
EDGE_ORPHANED = 'EDGE_ORPHANED',
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = {
|
||||||
|
[ErrorCode.MISSING_VIEWPORT_DIMENSIONS]: () => 'The Vue Flow parent container needs a width and a height to render the graph',
|
||||||
|
[ErrorCode.NODE_NOT_FOUND]: (id: string) => `Node not found\nNode: ${id}`,
|
||||||
|
[ErrorCode.NODE_MISSING_PARENT]: (id: string, parentId: string) => `Node is missing a parent\nNode: ${id}\nParent: ${parentId}`,
|
||||||
|
[ErrorCode.NODE_TYPE_MISSING]: (type: string) => `Node type is missing\nType: ${type}`,
|
||||||
|
[ErrorCode.NODE_EXTENT_INVALID]: (id: string) => `Only child nodes can use a parent extent\nNode: ${id}`,
|
||||||
|
[ErrorCode.EDGE_INVALID]: (id: string) => `An edge needs a source and a target\nEdge: ${id}`,
|
||||||
|
[ErrorCode.EDGE_SOURCE_MISSING]: (id: string, source: string) => `Edge source is missing\nEdge: ${id} \nSource: ${source}`,
|
||||||
|
[ErrorCode.EDGE_TARGET_MISSING]: (id: string, target: string) => `Edge target is missing\nEdge: ${id} \nTarget: ${target}`,
|
||||||
|
[ErrorCode.EDGE_TYPE_MISSING]: (type: string) => `Edge type is missing\nType: ${type}`,
|
||||||
|
[ErrorCode.EDGE_SOURCE_TARGET_SAME]: (id: string, source: string, target: string) =>
|
||||||
|
`Edge source and target are the same\nEdge: ${id} \nSource: ${source} \nTarget: ${target}`,
|
||||||
|
[ErrorCode.EDGE_SOURCE_TARGET_MISSING]: (id: string, source: string, target: string) =>
|
||||||
|
`Edge source or target is missing\nEdge: ${id} \nSource: ${source} \nTarget: ${target}`,
|
||||||
|
[ErrorCode.EDGE_ORPHANED]: (id: string) =>
|
||||||
|
`Edge was orphaned (suddenly missing source or target) and has been removed\nEdge: ${id}`,
|
||||||
|
[ErrorCode.EDGE_NOT_FOUND]: (id: string) => `Edge not found\nEdge: ${id}`,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export class VueFlowError<T extends ErrorCode = ErrorCode> extends Error {
|
||||||
|
code: T
|
||||||
|
constructor(
|
||||||
|
code: T,
|
||||||
|
...args: (typeof messages)[T] extends (...args: any[]) => string ? Parameters<(typeof messages)[T]> : never
|
||||||
|
) {
|
||||||
|
// @ts-expect-error - TS doesn't know that the message is a key of messages
|
||||||
|
super(messages[code]?.(...args))
|
||||||
|
|
||||||
|
this.code = code
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
const productionEnvs = ['production', 'prod']
|
const productionEnvs = ['production', 'prod']
|
||||||
|
|
||||||
export class VueFlowError extends Error {
|
|
||||||
constructor(message: string, scope?: string) {
|
|
||||||
super(`[Vue Flow]: ${scope ? `${scope} - ` : ''}${message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function warn(message: string, ...args: any[]) {
|
export function warn(message: string, ...args: any[]) {
|
||||||
if (!productionEnvs.includes(__ENV__ || '')) {
|
if (!productionEnvs.includes(__ENV__ || '')) {
|
||||||
console.warn(`[Vue Flow]: ${message}`, ...args)
|
console.warn(`[Vue Flow]: ${message}`, ...args)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Actions, Connection, Edge, GraphEdge, GraphNode, Node } from '~/types'
|
import type { Actions, Connection, Edge, GraphEdge, GraphNode, Node, State } from '~/types'
|
||||||
|
|
||||||
export const isDef = <T>(val: T): val is NonNullable<T> => typeof unref(val) !== 'undefined'
|
export const isDef = <T>(val: T): val is NonNullable<T> => typeof unref(val) !== 'undefined'
|
||||||
|
|
||||||
export function addEdgeToStore(edgeParams: Edge | Connection, edges: Edge[]) {
|
export function addEdgeToStore(edgeParams: Edge | Connection, edges: Edge[], onError: State['hooks']['error']['trigger']) {
|
||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
warn("Can't create edge. An edge needs a source and a target.")
|
onError(new VueFlowError(ErrorCode.EDGE_INVALID, (edgeParams as Edge).id))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,16 +31,17 @@ export function updateEdgeAction(
|
|||||||
edges: GraphEdge[],
|
edges: GraphEdge[],
|
||||||
findEdge: Actions['findEdge'],
|
findEdge: Actions['findEdge'],
|
||||||
shouldReplaceId: boolean,
|
shouldReplaceId: boolean,
|
||||||
|
onError: State['hooks']['error']['trigger'],
|
||||||
) {
|
) {
|
||||||
if (!newConnection.source || !newConnection.target) {
|
if (!newConnection.source || !newConnection.target) {
|
||||||
warn("Can't create new edge. An edge needs a source and a target.")
|
onError(new VueFlowError(ErrorCode.EDGE_INVALID, edge.id))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundEdge = findEdge(edge.id)
|
const foundEdge = findEdge(edge.id)
|
||||||
|
|
||||||
if (!foundEdge) {
|
if (!foundEdge) {
|
||||||
warn(`The old edge with id=${edge.id} does not exist.`)
|
onError(new VueFlowError(ErrorCode.EDGE_NOT_FOUND, edge.id))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +61,12 @@ export function updateEdgeAction(
|
|||||||
return newEdge
|
return newEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createGraphNodes(nodes: Node[], findNode: Actions['findNode'], currGraphNodes: GraphNode[]) {
|
export function createGraphNodes(
|
||||||
|
nodes: Node[],
|
||||||
|
currGraphNodes: GraphNode[],
|
||||||
|
findNode: Actions['findNode'],
|
||||||
|
onError: State['hooks']['error']['trigger'],
|
||||||
|
) {
|
||||||
const parentNodes: Record<string, true> = {}
|
const parentNodes: Record<string, true> = {}
|
||||||
|
|
||||||
const graphNodes = nodes.map((node) => {
|
const graphNodes = nodes.map((node) => {
|
||||||
@@ -82,7 +88,7 @@ export function createGraphNodes(nodes: Node[], findNode: Actions['findNode'], c
|
|||||||
const parentNode = nextNodes.find((n) => n.id === node.parentNode)
|
const parentNode = nextNodes.find((n) => n.id === node.parentNode)
|
||||||
|
|
||||||
if (node.parentNode && !parentNode) {
|
if (node.parentNode && !parentNode) {
|
||||||
warn(`Parent node ${node.parentNode} not found`)
|
onError(new VueFlowError(ErrorCode.NODE_MISSING_PARENT, node.id, node.parentNode))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.parentNode || parentNodes[node.id]) {
|
if (node.parentNode || parentNodes[node.id]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user