feat(handle): Add onClick handler

* for touch enabled connections
This commit is contained in:
Braks
2022-04-04 21:42:48 +02:00
parent 728046505c
commit b42c1b02de
7 changed files with 64 additions and 17 deletions
+9 -3
View File
@@ -4,7 +4,7 @@ import { Position } from '../../types'
import { NodeId } from '../../context' import { NodeId } from '../../context'
import type { HandleProps } from '../../types/handle' import type { HandleProps } from '../../types/handle'
const { id, hooks } = useVueFlow() const { id, hooks, connectionStartHandle } = useVueFlow()
const props = withDefaults(defineProps<HandleProps>(), { const props = withDefaults(defineProps<HandleProps>(), {
type: 'source', type: 'source',
position: 'top' as Position, position: 'top' as Position,
@@ -13,11 +13,12 @@ const props = withDefaults(defineProps<HandleProps>(), {
const nodeId = inject(NodeId, '') const nodeId = inject(NodeId, '')
const handler = useHandle() const { onMouseDown, onClick } = useHandle()
const onMouseDownHandler = (event: MouseEvent) => const onMouseDownHandler = (event: MouseEvent) =>
handler(event, props.id, nodeId, props.type === 'target', props.isValidConnection, undefined, (connection) => onMouseDown(event, props.id ?? null, nodeId, props.type === 'target', props.isValidConnection, undefined, (connection) =>
hooks.value.connect.trigger(connection), hooks.value.connect.trigger(connection),
) )
const onClickHandler = (event: MouseEvent) => onClick(event, props.id ?? null, nodeId, props.type, props.isValidConnection)
</script> </script>
<script lang="ts"> <script lang="ts">
export default { export default {
@@ -38,9 +39,14 @@ export default {
source: props.type !== 'target', source: props.type !== 'target',
target: props.type === 'target', target: props.type === 'target',
connectable: props.connectable, connectable: props.connectable,
connecting:
connectionStartHandle?.nodeId === nodeId &&
connectionStartHandle?.handleId === props.id &&
connectionStartHandle?.type === props.type,
}, },
]" ]"
@mousedown="onMouseDownHandler" @mousedown="onMouseDownHandler"
@click="onClickHandler"
> >
<slot :node-id="nodeId" v-bind="props"></slot> <slot :node-id="nodeId" v-bind="props"></slot>
</div> </div>
+50 -4
View File
@@ -15,7 +15,7 @@ export const checkElementBelowIsValid = (
connectionMode: ConnectionMode, connectionMode: ConnectionMode,
isTarget: boolean, isTarget: boolean,
nodeId: string, nodeId: string,
handleId: string, handleId: string | null,
isValidConnection: ValidConnectionFunc, isValidConnection: ValidConnectionFunc,
doc: Document, doc: Document,
) => { ) => {
@@ -67,10 +67,10 @@ const resetRecentHandle = (hoveredHandle: Element): void => {
hoveredHandle?.classList.remove('vue-flow__handle-connecting') hoveredHandle?.classList.remove('vue-flow__handle-connecting')
} }
export default (store: FlowStore = useVueFlow().store) => export default (store: FlowStore = useVueFlow().store) => {
( const onMouseDown = (
event: MouseEvent, event: MouseEvent,
handleId: string, handleId: string | null,
nodeId: string, nodeId: string,
isTarget: boolean, isTarget: boolean,
isValidConnection?: ValidConnectionFunc, isValidConnection?: ValidConnectionFunc,
@@ -173,3 +173,49 @@ export default (store: FlowStore = useVueFlow().store) =>
doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject) doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject)
doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject) doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject)
} }
const onClick = (
event: MouseEvent,
handleId: string | null,
nodeId: string,
handleType: HandleType,
isValidConnection?: ValidConnectionFunc,
) => {
if (!store.connectOnClick) return
if (!store.connectionStartHandle) {
store.hooks.connectStart.trigger({ event, nodeId, handleId, handleType })
store.setState({ connectionStartHandle: { nodeId, type: handleType, handleId } })
} else {
let validConnectFunc: ValidConnectionFunc = isValidConnection ?? (() => true)
const node = store.getNode(nodeId)
if (node && (typeof node.connectable === 'undefined' ? store.nodesConnectable : node.connectable) === false) return
if (!isValidConnection) {
if (node) validConnectFunc = (handleType !== 'target' ? node.isValidTargetPos : node.isValidSourcePos) ?? (() => true)
}
const doc = getHostForElement(event.target as HTMLElement)
const { connection, isValid } = checkElementBelowIsValid(
event as MouseEvent,
store.connectionMode,
store.connectionStartHandle.type === 'target',
store.connectionStartHandle.nodeId,
store.connectionStartHandle.handleId || null,
validConnectFunc,
doc,
)
store.hooks.connectStop.trigger(event)
if (isValid) store.hooks.connect.trigger(connection)
store.hooks.connectEnd.trigger(event)
store.setState({ connectionStartHandle: null })
}
}
return {
onMouseDown,
onClick,
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ export type OnConnectStartParams = {
/** Source node id */ /** Source node id */
nodeId?: string nodeId?: string
/** Source handle id */ /** Source handle id */
handleId?: string handleId: string | null
/** Source handle type */ /** Source handle type */
handleType?: HandleType handleType?: HandleType
} }
+1 -1
View File
@@ -1,5 +1,5 @@
import { CSSProperties, ToRefs } from 'vue' import { CSSProperties, ToRefs } from 'vue'
import { GraphEdge, Edge, DefaultEdgeOptions } from "./edge"; import { GraphEdge, Edge, DefaultEdgeOptions } from './edge'
import { GraphNode, CoordinateExtent, Node } from './node' import { GraphNode, CoordinateExtent, Node } from './node'
import { ConnectionLineType, ConnectionMode } from './connection' import { ConnectionLineType, ConnectionMode } from './connection'
import { KeyCode, PanOnScrollMode, UseZoomPanHelper } from './zoom' import { KeyCode, PanOnScrollMode, UseZoomPanHelper } from './zoom'
+1 -1
View File
@@ -21,7 +21,7 @@ export interface HandleProps {
/** Unique id of handle element */ /** Unique id of handle element */
id?: string id?: string
/** Handle type (source / target) {@link HandleType} */ /** Handle type (source / target) {@link HandleType} */
type?: string type?: HandleType
/** Handle position (top, bottom, left, right) {@link Position} */ /** Handle position (top, bottom, left, right) {@link Position} */
position?: Position position?: Position
/** A valid connection func {@link ValidConnectionFunc} */ /** A valid connection func {@link ValidConnectionFunc} */
-5
View File
@@ -72,8 +72,3 @@ export interface NodeProps<T = any> {
children?: Node<T>[] children?: Node<T>[]
dragHandle?: string dragHandle?: string
} }
export type NodeBounds = XYPosition & {
width: number | null
height: number | null
}
+2 -2
View File
@@ -31,8 +31,8 @@ export const getHandlePosition = (position: Position, rect: Rect, handle?: Handl
} }
} }
export const getHandle = (bounds?: HandleElement[], handleId?: string): HandleElement | undefined => { export const getHandle = (bounds: HandleElement[] = [], handleId: string | null): HandleElement | undefined => {
if (!bounds) return undefined if (!bounds.length) return undefined
// there is no handleId when there are no multiple handles/ handles with ids // there is no handleId when there are no multiple handles/ handles with ids
// so we just pick the first one // so we just pick the first one