refactor(core): add connection start and end handles to store state
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,7 @@ const { sourceNode } = defineProps<{ sourceNode: GraphNode }>()
|
|||||||
const {
|
const {
|
||||||
connectionMode,
|
connectionMode,
|
||||||
connectionStartHandle,
|
connectionStartHandle,
|
||||||
|
connectionEndHandle,
|
||||||
connectionPosition,
|
connectionPosition,
|
||||||
connectionLineType,
|
connectionLineType,
|
||||||
connectionLineStyle,
|
connectionLineStyle,
|
||||||
@@ -30,9 +31,7 @@ const handleId = $computed(() => connectionStartHandle!.handleId)
|
|||||||
|
|
||||||
const type = computed(() => connectionStartHandle!.type)
|
const type = computed(() => connectionStartHandle!.type)
|
||||||
|
|
||||||
const targetNode = $computed(
|
const targetNode = $computed(() => (connectionEndHandle?.handleId && findNode(connectionEndHandle.handleId)) || null)
|
||||||
() => (connectionStartHandle?.result && findNode(connectionStartHandle.result.connection.target)) || null,
|
|
||||||
)
|
|
||||||
|
|
||||||
const sourceHandle = $computed(
|
const sourceHandle = $computed(
|
||||||
() =>
|
() =>
|
||||||
@@ -45,13 +44,13 @@ const sourceHandle = $computed(
|
|||||||
const targetHandle = $computed(() => {
|
const targetHandle = $computed(() => {
|
||||||
return (
|
return (
|
||||||
(targetNode &&
|
(targetNode &&
|
||||||
connectionStartHandle?.result?.handleId &&
|
connectionEndHandle?.handleId &&
|
||||||
((connectionMode === ConnectionMode.Strict
|
((connectionMode === ConnectionMode.Strict
|
||||||
? targetNode.handleBounds[type.value === 'source' ? 'target' : 'source']?.find(
|
? targetNode.handleBounds[type.value === 'source' ? 'target' : 'source']?.find(
|
||||||
(d) => d.id === connectionStartHandle?.result?.handleId,
|
(d) => d.id === connectionEndHandle?.handleId,
|
||||||
)
|
)
|
||||||
: [...(targetNode.handleBounds.source || []), ...(targetNode.handleBounds.target || [])]?.find(
|
: [...(targetNode.handleBounds.source || []), ...(targetNode.handleBounds.target || [])]?.find(
|
||||||
(d) => d.id === connectionStartHandle?.result?.handleId,
|
(d) => d.id === connectionEndHandle?.handleId,
|
||||||
)) ||
|
)) ||
|
||||||
targetNode.handleBounds[type.value ?? 'target']?.[0])) ||
|
targetNode.handleBounds[type.value ?? 'target']?.[0])) ||
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ const emits = defineEmits<{
|
|||||||
|
|
||||||
const type = toRef(props, 'type', 'source')
|
const type = toRef(props, 'type', 'source')
|
||||||
|
|
||||||
const { connectionStartHandle, vueFlowRef, nodesConnectable, noDragClassName } = useVueFlow()
|
const { connectionStartHandle, connectionClickStartHandle, connectionEndHandle, vueFlowRef, nodesConnectable, noDragClassName } =
|
||||||
|
useVueFlow()
|
||||||
|
|
||||||
const { id: nodeId, node, nodeEl, connectedEdges } = useNode()
|
const { id: nodeId, node, nodeEl, connectedEdges } = useNode()
|
||||||
|
|
||||||
@@ -58,10 +59,19 @@ const isConnectable = computed(() => {
|
|||||||
|
|
||||||
const isConnecting = computed(
|
const isConnecting = computed(
|
||||||
() =>
|
() =>
|
||||||
connectionStartHandle.value &&
|
(connectionStartHandle.value?.nodeId === nodeId &&
|
||||||
connectionStartHandle.value.nodeId === nodeId &&
|
connectionStartHandle.value?.handleId === handleId.value &&
|
||||||
connectionStartHandle.value.handleId === handleId.value &&
|
connectionStartHandle.value?.type === type.value) ||
|
||||||
connectionStartHandle.value.type === type.value,
|
(connectionEndHandle.value?.nodeId === nodeId &&
|
||||||
|
connectionEndHandle.value?.handleId === handleId.value &&
|
||||||
|
connectionEndHandle.value?.type === type.value),
|
||||||
|
)
|
||||||
|
|
||||||
|
const isClickConnecting = computed(
|
||||||
|
() =>
|
||||||
|
connectionClickStartHandle.value?.nodeId === nodeId &&
|
||||||
|
connectionClickStartHandle.value?.handleId === handleId.value &&
|
||||||
|
connectionClickStartHandle.value?.type === type.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
// set up handle bounds if they don't exist yet and the node has been initialized (i.e. the handle was added after the node has already been mounted)
|
// set up handle bounds if they don't exist yet and the node has been initialized (i.e. the handle was added after the node has already been mounted)
|
||||||
@@ -109,7 +119,7 @@ function onPointerDown(event: MouseEvent | TouchEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onClick(event: MouseEvent) {
|
function onClick(event: MouseEvent) {
|
||||||
if (!connectionStartHandle && !connectableStart) {
|
if (!nodeId || (!connectionStartHandle && !connectableStart)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +151,10 @@ export default {
|
|||||||
type,
|
type,
|
||||||
{
|
{
|
||||||
connectable: isConnectable,
|
connectable: isConnectable,
|
||||||
connecting: isConnecting,
|
connecting: isClickConnecting,
|
||||||
connectablestart: connectableStart,
|
connectablestart: connectableStart,
|
||||||
connectableend: connectableEnd,
|
connectableend: connectableEnd,
|
||||||
connectionindicator: (isConnectable && connectableStart && !isConnecting) || (connectableEnd && isConnecting),
|
connectionindicator: isConnectable && ((connectableStart && !isConnecting) || (connectableEnd && isConnecting)),
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
@mousedown="onPointerDown"
|
@mousedown="onPointerDown"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function useHandle({
|
|||||||
const doc = getHostForElement(event.target as HTMLElement)
|
const doc = getHostForElement(event.target as HTMLElement)
|
||||||
|
|
||||||
if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
|
if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
|
||||||
const node = findNode(unref(nodeId))
|
const node = findNode(nodeId.value)
|
||||||
|
|
||||||
let isValidConnectionHandler = isValidConnection || isValidConnectionProp.value || alwaysValid
|
let isValidConnectionHandler = isValidConnection || isValidConnectionProp.value || alwaysValid
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ export default function useHandle({
|
|||||||
|
|
||||||
const { x, y } = getEventPosition(event)
|
const { x, y } = getEventPosition(event)
|
||||||
const clickedHandle = doc?.elementFromPoint(x, y)
|
const clickedHandle = doc?.elementFromPoint(x, y)
|
||||||
const handleType = getHandleType(unref(edgeUpdaterType), clickedHandle)
|
const handleType = getHandleType(edgeUpdaterType.value, clickedHandle)
|
||||||
const containerBounds = vueFlowRef.value?.getBoundingClientRect()
|
const containerBounds = vueFlowRef.value?.getBoundingClientRect()
|
||||||
|
|
||||||
if (!containerBounds || !handleType) {
|
if (!containerBounds || !handleType) {
|
||||||
@@ -160,7 +160,7 @@ export default function useHandle({
|
|||||||
viewport.value,
|
viewport.value,
|
||||||
)
|
)
|
||||||
: connectionPosition,
|
: connectionPosition,
|
||||||
result,
|
result.endHandle,
|
||||||
getConnectionStatus(!!prevClosestHandle, isValid),
|
getConnectionStatus(!!prevClosestHandle, isValid),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -229,11 +229,11 @@ export default function useHandle({
|
|||||||
if (!connectionClickStartHandle.value) {
|
if (!connectionClickStartHandle.value) {
|
||||||
emits.clickConnectStart({ event, nodeId: nodeId.value, handleId: handleId.value })
|
emits.clickConnectStart({ event, nodeId: nodeId.value, handleId: handleId.value })
|
||||||
|
|
||||||
startConnection({ nodeId: unref(nodeId), type: unref(type), handleId: unref(handleId) }, undefined, event, true)
|
startConnection({ nodeId: nodeId.value, type: unref(type), handleId: handleId.value }, undefined, event, true)
|
||||||
} else {
|
} else {
|
||||||
let isValidConnectionHandler = isValidConnection || isValidConnectionProp.value || alwaysValid
|
let isValidConnectionHandler = isValidConnection || isValidConnectionProp.value || alwaysValid
|
||||||
|
|
||||||
const node = findNode(unref(nodeId))
|
const node = findNode(nodeId.value)
|
||||||
|
|
||||||
if (!isValidConnectionHandler && node) {
|
if (!isValidConnectionHandler && node) {
|
||||||
isValidConnectionHandler = (!isTarget ? node.isValidTargetPos : node.isValidSourcePos) || alwaysValid
|
isValidConnectionHandler = (!isTarget ? node.isValidTargetPos : node.isValidSourcePos) || alwaysValid
|
||||||
|
|||||||
@@ -483,15 +483,16 @@ export function useActions(state: State, getters: ComputedGetters): Actions {
|
|||||||
state.connectionStartHandle = startHandle
|
state.connectionStartHandle = startHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.connectionEndHandle = null
|
||||||
state.connectionStatus = null
|
state.connectionStatus = null
|
||||||
|
|
||||||
if (position) state.connectionPosition = position
|
if (position) state.connectionPosition = position
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateConnection: Actions['updateConnection'] = (position, result, status = null) => {
|
const updateConnection: Actions['updateConnection'] = (position, result = null, status = null) => {
|
||||||
if (state.connectionStartHandle) {
|
if (state.connectionStartHandle) {
|
||||||
state.connectionPosition = position
|
state.connectionPosition = position
|
||||||
state.connectionStartHandle.result = result
|
state.connectionEndHandle = result
|
||||||
state.connectionStatus = status
|
state.connectionStatus = status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ function defaultState(): State {
|
|||||||
},
|
},
|
||||||
connectionMode: ConnectionMode.Loose,
|
connectionMode: ConnectionMode.Loose,
|
||||||
connectionStartHandle: null,
|
connectionStartHandle: null,
|
||||||
|
connectionEndHandle: null,
|
||||||
connectionClickStartHandle: null,
|
connectionClickStartHandle: null,
|
||||||
connectionPosition: { x: NaN, y: NaN },
|
connectionPosition: { x: NaN, y: NaN },
|
||||||
connectionRadius: 20,
|
connectionRadius: 20,
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ export interface ConnectionHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ValidHandleResult {
|
export interface ValidHandleResult {
|
||||||
handleId: string | null
|
endHandle: ConnectingHandle | null
|
||||||
handleDomNode: Element | null
|
handleDomNode: Element | null
|
||||||
isValid: boolean
|
isValid: boolean
|
||||||
connection: Connection
|
connection: Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StartHandle {
|
export interface ConnectingHandle {
|
||||||
nodeId: string
|
nodeId: string
|
||||||
type: HandleType
|
type: HandleType
|
||||||
handleId: string | null
|
handleId: string | null
|
||||||
result?: ValidHandleResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A valid connection function can determine if an attempted connection is valid or not, i.e. abort creating a new edge */
|
/** A valid connection function can determine if an attempted connection is valid or not, i.e. abort creating a new edge */
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import type { CoordinateExtent, GraphNode, Node } from './node'
|
|||||||
import type { D3Selection, D3Zoom, D3ZoomHandler, PanOnScrollMode, ViewportFunctions, ViewportTransform } from './zoom'
|
import type { D3Selection, D3Zoom, D3ZoomHandler, PanOnScrollMode, ViewportFunctions, ViewportTransform } from './zoom'
|
||||||
import type { CustomEvent, FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks'
|
import type { CustomEvent, FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks'
|
||||||
import type { EdgeChange, NodeChange, NodeDragItem } from './changes'
|
import type { EdgeChange, NodeChange, NodeDragItem } from './changes'
|
||||||
import type { StartHandle, ValidConnectionFunc, ValidHandleResult } from './handle'
|
import type { ConnectingHandle, ValidConnectionFunc } from './handle'
|
||||||
|
|
||||||
export interface UpdateNodeDimensionsParams {
|
export interface UpdateNodeDimensionsParams {
|
||||||
id: string
|
id: string
|
||||||
@@ -84,8 +84,9 @@ export interface State extends Omit<FlowOptions, 'id' | 'modelValue'> {
|
|||||||
connectionLineType: ConnectionLineType | null
|
connectionLineType: ConnectionLineType | null
|
||||||
/** @deprecated use {@link ConnectionLineOptions.style} */
|
/** @deprecated use {@link ConnectionLineOptions.style} */
|
||||||
connectionLineStyle: CSSProperties | null
|
connectionLineStyle: CSSProperties | null
|
||||||
connectionStartHandle: StartHandle | null
|
connectionStartHandle: ConnectingHandle | null
|
||||||
connectionClickStartHandle: StartHandle | null
|
connectionEndHandle: ConnectingHandle | null
|
||||||
|
connectionClickStartHandle: ConnectingHandle | null
|
||||||
connectionPosition: XYPosition
|
connectionPosition: XYPosition
|
||||||
connectionRadius: number
|
connectionRadius: number
|
||||||
connectionStatus: ConnectionStatus | null
|
connectionStatus: ConnectionStatus | null
|
||||||
@@ -247,9 +248,14 @@ export interface Actions extends ViewportFunctions {
|
|||||||
/** force update node internal data, if handle bounds are incorrect, you might want to use this */
|
/** force update node internal data, if handle bounds are incorrect, you might want to use this */
|
||||||
updateNodeInternals: UpdateNodeInternals
|
updateNodeInternals: UpdateNodeInternals
|
||||||
/** start a connection */
|
/** start a connection */
|
||||||
startConnection: (startHandle: StartHandle, position?: XYPosition, event?: MouseEvent | TouchEvent, isClick?: boolean) => void
|
startConnection: (
|
||||||
|
startHandle: ConnectingHandle,
|
||||||
|
position?: XYPosition,
|
||||||
|
event?: MouseEvent | TouchEvent,
|
||||||
|
isClick?: boolean,
|
||||||
|
) => void
|
||||||
/** update connection position */
|
/** update connection position */
|
||||||
updateConnection: (position: XYPosition, result?: ValidHandleResult, status?: ConnectionStatus | null) => void
|
updateConnection: (position: XYPosition, result?: ConnectingHandle | null, status?: ConnectionStatus | null) => void
|
||||||
/** end (or cancel) a connection */
|
/** end (or cancel) a connection */
|
||||||
endConnection: (event?: MouseEvent | TouchEvent, isClick?: boolean) => void
|
endConnection: (event?: MouseEvent | TouchEvent, isClick?: boolean) => void
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export function isValidHandle(
|
|||||||
connectionMode: ConnectionMode,
|
connectionMode: ConnectionMode,
|
||||||
fromNodeId: string,
|
fromNodeId: string,
|
||||||
fromHandleId: string | null,
|
fromHandleId: string | null,
|
||||||
fromType: string,
|
fromType: HandleType,
|
||||||
isValidConnection: ValidConnectionFunc,
|
isValidConnection: ValidConnectionFunc,
|
||||||
doc: Document | ShadowRoot,
|
doc: Document | ShadowRoot,
|
||||||
edges: GraphEdge[],
|
edges: GraphEdge[],
|
||||||
@@ -92,10 +92,10 @@ export function isValidHandle(
|
|||||||
const handleToCheck = handleBelow?.classList.contains('vue-flow__handle') ? handleBelow : handleDomNode
|
const handleToCheck = handleBelow?.classList.contains('vue-flow__handle') ? handleBelow : handleDomNode
|
||||||
|
|
||||||
const result: ValidHandleResult = {
|
const result: ValidHandleResult = {
|
||||||
handleId: null,
|
|
||||||
handleDomNode: handleToCheck,
|
handleDomNode: handleToCheck,
|
||||||
isValid: false,
|
isValid: false,
|
||||||
connection: { source: '', target: '', sourceHandle: null, targetHandle: null },
|
connection: { source: '', target: '', sourceHandle: null, targetHandle: null },
|
||||||
|
endHandle: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handleToCheck) {
|
if (handleToCheck) {
|
||||||
@@ -113,7 +113,6 @@ export function isValidHandle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.connection = connection
|
result.connection = connection
|
||||||
result.handleId = handleId
|
|
||||||
|
|
||||||
const isConnectable = connectable && connectableEnd
|
const isConnectable = connectable && connectableEnd
|
||||||
|
|
||||||
@@ -125,6 +124,12 @@ export function isValidHandle(
|
|||||||
: handleNodeId !== fromNodeId || handleId !== fromHandleId)
|
: handleNodeId !== fromNodeId || handleId !== fromHandleId)
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
result.endHandle = {
|
||||||
|
nodeId: handleNodeId,
|
||||||
|
handleId,
|
||||||
|
type: handleType as HandleType,
|
||||||
|
}
|
||||||
|
|
||||||
result.isValid = isValidConnection(connection, {
|
result.isValid = isValidConnection(connection, {
|
||||||
edges,
|
edges,
|
||||||
sourceNode: findNode(connection.source)!,
|
sourceNode: findNode(connection.source)!,
|
||||||
|
|||||||
Reference in New Issue
Block a user