diff --git a/examples/vite.config.ts b/examples/vite.config.ts index 914bfbfb..163f832a 100644 --- a/examples/vite.config.ts +++ b/examples/vite.config.ts @@ -13,11 +13,13 @@ export default defineConfig({ }, }, plugins: [ - vue(), + vue({ + reactivityTransform: true, + }), vueTypes(), svgLoader(), AutoImport({ - imports: ['vue', '@vueuse/core'], + imports: ['vue', '@vueuse/core', 'vue/macros'], dts: resolve('src/auto-imports.d.ts'), }), ], diff --git a/package/src/components/Edges/EdgeWrapper.vue b/package/src/components/Edges/EdgeWrapper.vue index ecae2c4f..a6d2bd33 100644 --- a/package/src/components/Edges/EdgeWrapper.vue +++ b/package/src/components/Edges/EdgeWrapper.vue @@ -3,7 +3,6 @@ import { CSSProperties } from 'vue' import { useHandle, useVueFlow } from '../../composables' import { ConnectionMode, EdgeComponent, GraphEdge, GraphNode, Position } from '../../types' import { getEdgePositions, getHandle, getMarkerId } from '../../utils' -import { Slots } from '../../context' import EdgeAnchor from './EdgeAnchor' interface EdgeWrapper { @@ -13,21 +12,13 @@ interface EdgeWrapper { targetNode: GraphNode selectable?: boolean updatable?: boolean + type: EdgeComponent | Function | Object | false + name: string } -const { id, edge, sourceNode, targetNode, selectable, updatable } = defineProps() +const { id, edge, name, sourceNode, targetNode, selectable, updatable, type } = defineProps() -const slots = inject(Slots) - -const { hooks, connectionMode, edgeUpdaterRadius, noPanClassName, setState, getEdge, addSelectedEdges, getEdgeTypes } = $( - useVueFlow(), -) - -let name = $ref(edge.type ?? 'default') -watch( - () => edge.type, - (v) => v && (name = v), -) +const { hooks, connectionMode, edgeUpdaterRadius, noPanClassName, setState, getEdge, addSelectedEdges } = $(useVueFlow()) let updating = $ref(false) @@ -81,31 +72,28 @@ const handleEdgeUpdater = (event: MouseEvent, isSourceHandle: boolean) => { ) } -// when connection type is loose we can define all handles as sources -const targetNodeHandles = $computed(() => { +const sourceHandle = $computed(() => { + let sourceNodeHandles if (connectionMode === ConnectionMode.Strict) { - return targetNode.handleBounds.target + sourceNodeHandles = sourceNode.handleBounds.source + } else { + sourceNodeHandles = sourceNode.handleBounds.source ?? sourceNode.handleBounds.target } - const targetBounds = targetNode.handleBounds.target - const sourceBounds = targetNode.handleBounds.source - return targetBounds ?? sourceBounds + return getHandle(sourceNodeHandles, edge.sourceHandle) }) -const sourceNodeHandles = $computed(() => { +const targetHandle = $computed(() => { + let targetNodeHandles if (connectionMode === ConnectionMode.Strict) { - return sourceNode.handleBounds.source + targetNodeHandles = targetNode.handleBounds.target + } else { + targetNodeHandles = targetNode.handleBounds.target ?? targetNode.handleBounds.source } - const targetBounds = sourceNode.handleBounds.target - const sourceBounds = sourceNode.handleBounds.source - return sourceBounds ?? targetBounds + return getHandle(targetNodeHandles, edge.targetHandle) }) -const sourceHandle = $computed(() => getHandle(sourceNodeHandles, edge.sourceHandle)) - -const targetHandle = $computed(() => getHandle(targetNodeHandles, edge.targetHandle)) - const sourcePosition = $(controlledComputed($$(sourceHandle), () => (sourceHandle ? sourceHandle.position : Position.Bottom))) const targetPosition = $(controlledComputed($$(targetHandle), () => (targetHandle ? targetHandle.position : Position.Top))) @@ -115,8 +103,6 @@ onMounted(() => { [ $$(sourcePosition), $$(targetPosition), - () => sourceNode.position, - () => targetNode.position, () => sourceNode.computedPosition, () => targetNode.computedPosition, () => sourceNode.dimensions, @@ -132,42 +118,17 @@ onMounted(() => { targetPosition, ) - const edge = getEdge(id)! - - if (edge.sourceX !== sourceX) edge.sourceX = sourceX - if (edge.sourceY !== sourceY) edge.sourceY = sourceY - if (edge.targetX !== targetX) edge.targetX = targetX - if (edge.targetY !== targetY) edge.targetY = targetY + const storedEdge = getEdge(id)! + if (edge.sourceX !== sourceX) storedEdge.sourceX = sourceX + if (edge.sourceY !== sourceY) storedEdge.sourceY = sourceY + if (edge.targetX !== targetX) storedEdge.targetX = targetX + if (edge.targetY !== targetY) storedEdge.targetY = targetY }, - { immediate: true }, + { immediate: true, flush: 'post' }, ) }) -const type = computed(() => { - let edgeType = edge.template ?? getEdgeTypes[name] - const instance = getCurrentInstance() - - if (typeof edgeType === 'string') { - if (instance) { - const components = Object.keys(instance.appContext.components) - if (components && components.includes(name)) { - edgeType = resolveComponent(name, false) as EdgeComponent - } - } - } - if (typeof edgeType !== 'string') return edgeType - - const slot = slots?.[`edge-${name}`] - if (!slot?.({})) { - console.warn(`[vueflow]: Edge type "${edge.type}" not found and no edge-slot detected. Using fallback type "default".`) - name = 'default' - return getEdgeTypes.default - } - - return slot -}) - -const getClass = computed(() => { +const getClass = () => { const extraClass = edge.class instanceof Function ? edge.class(edge) : edge.class return [ 'vue-flow__edge', @@ -181,7 +142,7 @@ const getClass = computed(() => { }, extraClass, ] -}) +} const getStyle = () => (edge.style instanceof Function ? edge.style(edge) : edge.style) as CSSProperties @@ -193,7 +154,7 @@ export default { diff --git a/package/src/components/Nodes/NodeWrapper.vue b/package/src/components/Nodes/NodeWrapper.vue index 7c8bade0..98a0b59b 100644 --- a/package/src/components/Nodes/NodeWrapper.vue +++ b/package/src/components/Nodes/NodeWrapper.vue @@ -3,24 +3,25 @@ import { useDraggableCore } from '@braks/revue-draggable' import { CSSProperties } from 'vue' import { useVueFlow } from '../../composables' import { GraphNode, NodeComponent, SnapGrid } from '../../types' -import { NodeId, Slots } from '../../context' +import { NodeId } from '../../context' import { getHandleBounds, getXYZPos } from '../../utils' interface NodeWrapperProps { id: string node: GraphNode + parentNode?: GraphNode draggable: boolean selectable: boolean connectable: boolean snapGrid?: SnapGrid + type: NodeComponent | Function | Object | false + name: string } -const { id, node, draggable, selectable, connectable, snapGrid } = defineProps() +const { id, type, name, node, parentNode, draggable, selectable, connectable, snapGrid } = defineProps() provide(NodeId, id) -const slots = inject(Slots) - const { viewport, noDragClassName, @@ -35,12 +36,6 @@ const { addSelectedNodes, } = $(useVueFlow()) -let name = $ref(node.type ?? 'default') -watch( - () => node.type, - (v) => v && (name = v), -) - const nodeElement = ref() const { scale, disabled, handle, cancel, grid, onDrag, onDragStart, onDragStop } = useDraggableCore(nodeElement, { @@ -91,6 +86,8 @@ onMounted(() => { ) }) +const parent = $computed(() => (node.parentNode ? getNode(node.parentNode) : undefined)) + onMounted(() => { const observer = useResizeObserver(nodeElement, () => updateNodeDimensions([{ id: node.id, nodeElement: nodeElement.value, forceUpdate: true }]), @@ -109,29 +106,27 @@ onMounted(() => { updateNodeDimensions([{ id: node.id, nodeElement: nodeElement.value, forceUpdate: true }]) }) -watch( - [ - () => node.position, - () => getNode(node.parentNode!)?.computedPosition, - () => node.selected, - () => getNode(node.parentNode!)?.selected, - ], - ([pos, parent]) => { - const xyzPos = { - ...pos, - z: node.dragging || node.selected ? 1000 : 0, - } +onMounted(() => { + watch( + [() => node.position, () => parent?.computedPosition, () => node.selected, () => parent?.selected], + ([pos, parent]) => { + const xyzPos = { + ...pos, + z: node.dragging || node.selected ? 1000 : 0, + } + const graphNode = getNode(id)! - if (parent) { - getNode(id)!.computedPosition = getXYZPos(parent, xyzPos) - } else { - getNode(id)!.computedPosition = xyzPos - } + if (parent) { + graphNode.computedPosition = getXYZPos(parent, xyzPos) + } else { + graphNode.computedPosition = xyzPos + } - getNode(id)!.handleBounds = getHandleBounds(nodeElement.value, scale.value) - }, - { deep: true, flush: 'post' }, -) + graphNode.handleBounds = getHandleBounds(nodeElement.value, scale.value) + }, + { deep: true, flush: 'post' }, + ) +}) onUnmounted(() => { nodeElement.value = undefined @@ -177,30 +172,6 @@ const onSelectNode = (event: MouseEvent) => { } } -const type = computed(() => { - let nodeType = node.template ?? getNodeTypes[name] - const instance = getCurrentInstance() - - if (typeof nodeType === 'string') { - if (instance) { - const components = Object.keys(instance.appContext.components) - if (components && components.includes(name)) { - nodeType = resolveComponent(name, false) as NodeComponent - } - } - } - if (typeof nodeType !== 'string') return nodeType - - const slot = slots?.[`node-${name}`] - if (!slot?.({})) { - console.warn(`[vueflow]: Node type "${node.type}" not found and no node-slot detected. Using fallback type "default".`) - name = 'default' - return getNodeTypes.default - } - - return slot -}) - onDragStart(({ event }) => { addSelectedNodes([]) hooks.nodeDragStart.trigger({ event, node }) @@ -280,7 +251,7 @@ export default { ref="nodeElement" :class="getClass" :style="getStyle" - :data-id="node.id" + :data-id="id" @mouseenter="onMouseEnter" @mousemove="onMouseMove" @mouseleave="onMouseLeave" diff --git a/package/src/container/EdgeRenderer/EdgeRenderer.vue b/package/src/container/EdgeRenderer/EdgeRenderer.vue index 832aefc6..1f1cadbb 100644 --- a/package/src/container/EdgeRenderer/EdgeRenderer.vue +++ b/package/src/container/EdgeRenderer/EdgeRenderer.vue @@ -3,8 +3,12 @@ import EdgeWrapper from '../../components/Edges/EdgeWrapper.vue' import ConnectionLine from '../../components/ConnectionLine/ConnectionLine.vue' import { useVueFlow } from '../../composables' import { groupEdgesByZLevel } from '../../utils' +import { EdgeComponent, GraphEdge } from '../../types' +import { Slots } from '../../context' import MarkerDefinitions from './MarkerDefinitions.vue' +const slots = inject(Slots) + const { connectionNodeId, nodesConnectable, @@ -14,6 +18,7 @@ const { elementsSelectable, getNode, getEdges, + getEdgeTypes, } = $(useVueFlow()) const sourceNode = $( @@ -42,6 +47,30 @@ const connectionLineVisible = $( const getNodeWrapped = (node: string) => getNode(node)! const groups = computed(() => groupEdgesByZLevel(getEdges, getNodeWrapped)) + +const getType = $computed(() => (edge: GraphEdge) => { + const name = edge.type || 'default' + let edgeType = edge.template ?? getEdgeTypes[name] + const instance = getCurrentInstance() + + if (typeof edgeType === 'string') { + if (instance) { + const components = Object.keys(instance.appContext.components) + if (components && components.includes(name)) { + edgeType = resolveComponent(name, false) as EdgeComponent + } + } + } + if (typeof edgeType !== 'string') return edgeType + + const slot = slots?.[`edge-${name}`] + if (!slot?.({})) { + console.warn(`[vueflow]: Edge type "${edge.type}" not found and no edge-slot detected. Using fallback type "default".`) + return false + } + + return slot +})