refactor(nodes): use HandleConnectable type for nodes connectable prop

This commit is contained in:
braks
2022-10-10 21:33:44 +02:00
committed by Braks
parent 0215d49ad3
commit 283846c196
5 changed files with 36 additions and 34 deletions
+19 -22
View File
@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { isString } from '@vueuse/core' import { isFunction, isString } from '@vueuse/core'
import { useHandle, useNode, useVueFlow } from '../../composables' import { useHandle, useNode, useVueFlow } from '../../composables'
import type { Position } from '../../types' import type { Position } from '../../types'
import { ConnectionMode } from '../../types' import { ConnectionMode } from '../../types'
@@ -8,7 +8,7 @@ import { getDimensions } from '../../utils'
const { type = 'source', position = 'top' as Position, connectable = true, id, isValidConnection } = defineProps<HandleProps>() const { type = 'source', position = 'top' as Position, connectable = true, id, isValidConnection } = defineProps<HandleProps>()
const { connectionStartHandle, connectionMode, vueFlowRef } = $(useVueFlow()) const { connectionStartHandle, connectionMode, vueFlowRef, nodesConnectable } = $(useVueFlow())
const { id: nodeId, node, nodeEl, connectedEdges } = useNode() const { id: nodeId, node, nodeEl, connectedEdges } = useNode()
@@ -19,6 +19,8 @@ const handleId = $computed(() => id ?? (connectionMode === ConnectionMode.Strict
const isConnectable = computed(() => { const isConnectable = computed(() => {
if (isString(connectable) && connectable === 'single') { if (isString(connectable) && connectable === 'single') {
return !connectedEdges.value.some((edge) => edge[type] === nodeId && edge[`${type}Handle`] === handleId) return !connectedEdges.value.some((edge) => edge[type] === nodeId && edge[`${type}Handle`] === handleId)
} else if (isFunction(connectable)) {
return connectable(node, connectedEdges.value)
} }
return connectable return connectable
@@ -34,25 +36,6 @@ const onClickHandler = (event: MouseEvent) => {
onClick(event, handleId ?? null, nodeId, type, isValidConnection) onClick(event, handleId ?? null, nodeId, type, isValidConnection)
} }
const getClasses = computed(() => {
return [
'vue-flow__handle',
`vue-flow__handle-${position}`,
`vue-flow__handle-${handleId}`,
'nodrag',
{
source: type !== 'target',
target: type === 'target',
connectable: isConnectable,
connecting:
connectionStartHandle &&
connectionStartHandle.nodeId === nodeId &&
connectionStartHandle.handleId === handleId &&
connectionStartHandle.type === type,
},
]
})
onMounted(() => { onMounted(() => {
const existingBounds = node.handleBounds[type]?.find((b) => b.id === handleId) const existingBounds = node.handleBounds[type]?.find((b) => b.id === handleId)
if (!vueFlowRef || existingBounds) return if (!vueFlowRef || existingBounds) return
@@ -92,7 +75,21 @@ export default {
:data-handleid="handleId" :data-handleid="handleId"
:data-nodeid="nodeId" :data-nodeid="nodeId"
:data-handlepos="position" :data-handlepos="position"
:class="getClasses" class="vue-flow__handle nodrag"
:class="[
`vue-flow__handle-${position}`,
`vue-flow__handle-${handleId}`,
{
source: type !== 'target',
target: type === 'target',
connectable: isConnectable,
connecting:
connectionStartHandle &&
connectionStartHandle.nodeId === nodeId &&
connectionStartHandle.handleId === handleId &&
connectionStartHandle.type === type,
},
]"
@mousedown="onMouseDownHandler" @mousedown="onMouseDownHandler"
@click="onClickHandler" @click="onClickHandler"
> >
@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useVModel } from '@vueuse/core' import { useVModel } from '@vueuse/core'
import { useDrag, useNodeHooks, useVueFlow } from '../../composables' import { useDrag, useNodeHooks, useVueFlow } from '../../composables'
import type { GraphNode, NodeComponent, SnapGrid, XYZPosition } from '../../types' import type { GraphNode, HandleConnectable, NodeComponent, SnapGrid, XYZPosition } from '../../types'
import { NodeId, NodeRef } from '../../context' import { NodeId, NodeRef } from '../../context'
import { getConnectedEdges, getXYZPos, handleNodeClick } from '../../utils' import { getConnectedEdges, getXYZPos, handleNodeClick } from '../../utils'
@@ -9,7 +9,7 @@ const { id, type, name, draggable, selectable, connectable, snapGrid, ...props }
id: string id: string
draggable: boolean draggable: boolean
selectable: boolean selectable: boolean
connectable: boolean connectable: HandleConnectable
snapGrid?: SnapGrid snapGrid?: SnapGrid
type: NodeComponent | Function | Object | false type: NodeComponent | Function | Object | false
name: string name: string
@@ -39,6 +39,8 @@ const node = $(useVModel(props, 'node'))
const parentNode = $computed(() => (node.parentNode ? getNode(node.parentNode) : undefined)) const parentNode = $computed(() => (node.parentNode ? getNode(node.parentNode) : undefined))
const connectedEdges = $computed(() => getConnectedEdges([node], edges))
const nodeElement = ref() const nodeElement = ref()
provide(NodeRef, nodeElement) provide(NodeRef, nodeElement)
@@ -137,19 +139,19 @@ onBeforeUnmount(() => {
const onMouseEnter = (event: MouseEvent) => { const onMouseEnter = (event: MouseEvent) => {
if (!dragging?.value) { if (!dragging?.value) {
emit.mouseEnter({ event, node, connectedEdges: getConnectedEdges([node], edges) }) emit.mouseEnter({ event, node, connectedEdges })
} }
} }
const onMouseMove = (event: MouseEvent) => { const onMouseMove = (event: MouseEvent) => {
if (!dragging?.value) { if (!dragging?.value) {
emit.mouseMove({ event, node, connectedEdges: getConnectedEdges([node], edges) }) emit.mouseMove({ event, node, connectedEdges })
} }
} }
const onMouseLeave = (event: MouseEvent) => { const onMouseLeave = (event: MouseEvent) => {
if (!dragging?.value) { if (!dragging?.value) {
emit.mouseLeave({ event, node, connectedEdges: getConnectedEdges([node], edges) }) emit.mouseLeave({ event, node, connectedEdges })
} }
} }
+2 -2
View File
@@ -24,9 +24,9 @@ export default function useNode<Data = ElementData, CustomEvents extends Record<
return { return {
id: nodeId, id: nodeId,
node,
nodeEl, nodeEl,
parentNode: node.parentNode ? findNode(node.parentNode) : undefined, node,
parentNode: computed(() => (node.parentNode ? findNode(node.parentNode) : undefined)),
connectedEdges: computed(() => getConnectedEdges([node], getEdges.value)), connectedEdges: computed(() => getConnectedEdges([node], getEdges.value)),
} }
} }
+4 -1
View File
@@ -22,6 +22,9 @@ export type ValidConnectionFunc = (
elements: { edges: GraphEdge[]; sourceNode: GraphNode; targetNode: GraphNode }, elements: { edges: GraphEdge[]; sourceNode: GraphNode; targetNode: GraphNode },
) => boolean ) => boolean
/** set to true to allow unlimited connections, single for only one connection or use a cb function to determine connect-ability */
export type HandleConnectable = boolean | 'single' | ((node: GraphNode, connectedEdges: GraphEdge[]) => boolean)
export interface HandleProps { export interface HandleProps {
/** Unique id of handle element */ /** Unique id of handle element */
id?: string id?: string
@@ -32,5 +35,5 @@ export interface HandleProps {
/** A valid connection func {@link ValidConnectionFunc} */ /** A valid connection func {@link ValidConnectionFunc} */
isValidConnection?: ValidConnectionFunc isValidConnection?: ValidConnectionFunc
/** Enable/disable connecting to handle */ /** Enable/disable connecting to handle */
connectable?: boolean | 'single' connectable?: HandleConnectable
} }
+4 -4
View File
@@ -1,7 +1,7 @@
import type { Component, VNode } from 'vue' import type { Component, VNode } from 'vue'
import type { ClassFunc, Dimensions, ElementData, Position, SnapGrid, StyleFunc, Styles, XYPosition, XYZPosition } from './flow' import type { ClassFunc, Dimensions, ElementData, Position, SnapGrid, StyleFunc, Styles, XYPosition, XYZPosition } from './flow'
import type { DefaultNodeTypes, NodeComponent } from './components' import type { DefaultNodeTypes, NodeComponent } from './components'
import type { HandleElement, ValidConnectionFunc } from './handle' import type { HandleConnectable, HandleElement, ValidConnectionFunc } from './handle'
import type { CustomEvent, NodeEventsHandler, NodeEventsOn } from './hooks' import type { CustomEvent, NodeEventsHandler, NodeEventsOn } from './hooks'
/** Defined as [[x-from, y-from], [x-to, y-to]] **/ /** Defined as [[x-from, y-from], [x-to, y-to]] **/
@@ -31,7 +31,7 @@ export interface Node<Data = ElementData, CustomEvents extends Record<string, Cu
sourcePosition?: Position sourcePosition?: Position
draggable?: boolean draggable?: boolean
selectable?: boolean selectable?: boolean
connectable?: boolean connectable?: HandleConnectable
dragHandle?: string dragHandle?: string
/** move on grid */ /** move on grid */
snapGrid?: SnapGrid snapGrid?: SnapGrid
@@ -93,8 +93,8 @@ export interface NodeProps<Data = ElementData, CustomEvents = {}> {
type: keyof DefaultNodeTypes | string type: keyof DefaultNodeTypes | string
/** is node selected */ /** is node selected */
selected: boolean selected: boolean
/** can node be connected */ /** can node handles be connected */
connectable: boolean connectable: HandleConnectable
/** node x, y (relative) position on graph */ /** node x, y (relative) position on graph */
position: XYPosition position: XYPosition
/** dom element dimensions (width, height) */ /** dom element dimensions (width, height) */