feat(core): add connectableStart & connectableEnd props

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
braks
2023-04-03 08:53:33 +02:00
committed by Braks
parent c46020fbc2
commit 1d3908db62
3 changed files with 71 additions and 17 deletions
+54 -9
View File
@@ -3,7 +3,21 @@ import { isFunction, isString } from '@vueuse/core'
import { Position } from '../../types' import { Position } from '../../types'
import type { HandleProps } from '../../types/handle' import type { HandleProps } from '../../types/handle'
const { position = Position.Top, connectable, id, isValidConnection, ...props } = defineProps<HandleProps>() const {
position = Position.Top,
connectable,
connectableStart = true,
connectableEnd = true,
id,
isValidConnection,
...props
} = defineProps<HandleProps>()
const emits = defineEmits<{
(event: 'mousedown', e: MouseEvent): void
(event: 'touchstart', e: TouchEvent): void
(event: 'click', e: MouseEvent): void
}>()
const type = toRef(props, 'type', 'source') const type = toRef(props, 'type', 'source')
@@ -42,6 +56,14 @@ const isConnectable = computed(() => {
return isDef(connectable) ? connectable : nodesConnectable.value return isDef(connectable) ? connectable : nodesConnectable.value
}) })
const isConnecting = computed(
() =>
connectionStartHandle &&
connectionStartHandle.nodeId === nodeId &&
connectionStartHandle.handleId === handleId &&
connectionStartHandle.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)
until(() => node.initialized) until(() => node.initialized)
.toBe(true, { flush: 'post' }) .toBe(true, { flush: 'post' })
@@ -71,6 +93,30 @@ until(() => node.initialized)
node.handleBounds[type.value] = [...(node.handleBounds[type.value] ?? []), nextBounds] node.handleBounds[type.value] = [...(node.handleBounds[type.value] ?? []), nextBounds]
}) })
function onPointerDown(event: MouseEvent | TouchEvent) {
const isMouseTriggered = isMouseEvent(event)
if (isConnectable.value && connectableStart && ((isMouseTriggered && event.button === 0) || !isMouseTriggered)) {
handlePointerDown(event)
}
if (isMouseTriggered) {
emits('mousedown', event)
} else {
emits('touchstart', event)
}
}
function onClick(event: MouseEvent) {
if (!connectionStartHandle && !connectableStart) {
return
}
if (isConnectable.value) {
handleClick(event)
}
}
</script> </script>
<script lang="ts"> <script lang="ts">
@@ -95,16 +141,15 @@ export default {
type, type,
{ {
connectable: isConnectable, connectable: isConnectable,
connecting: connecting: isConnecting,
connectionStartHandle && connectablestart: connectableStart,
connectionStartHandle.nodeId === nodeId && connectableend: connectableEnd,
connectionStartHandle.handleId === handleId && connectionindicator: (isConnectable && connectableStart && !isConnecting) || (connectableEnd && isConnecting),
connectionStartHandle.type === type,
}, },
]" ]"
@mousedown="handlePointerDown" @mousedown="onPointerDown"
@touchstart.passive="handlePointerDown" @touchstart.passive="onPointerDown"
@click="handleClick" @click="onClick"
> >
<slot :id="id" /> <slot :id="id" />
</div> </div>
+5 -1
View File
@@ -58,6 +58,10 @@ export interface HandleProps {
position?: Position position?: Position
/** 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 altogether */
connectable?: HandleConnectable connectable?: HandleConnectable
/** Can this handle be used to *start* a connection */
connectableStart?: boolean
/** Can this handle be used to *end* a connection */
connectableEnd?: boolean
} }
+12 -7
View File
@@ -98,25 +98,30 @@ export function isValidHandle(
connection: { source: '', target: '', sourceHandle: null, targetHandle: null }, connection: { source: '', target: '', sourceHandle: null, targetHandle: null },
} }
if (handleToCheck && handleDomNode && handle) { if (handleToCheck) {
const handleNodeId = handleDomNode.getAttribute('data-nodeid') const handleType = getHandleType(undefined, handleToCheck)
const handleId = handleDomNode.getAttribute('data-handleid') const handleNodeId = handleToCheck.getAttribute('data-nodeid')!
const handleId = handleToCheck.getAttribute('data-handleid')
const connectable = handleToCheck.classList.contains('connectable')
const connectableEnd = handleToCheck.classList.contains('connectableend')
const connection: Connection = { const connection: Connection = {
source: isTarget ? handle.nodeId : fromNodeId, source: isTarget ? handleNodeId : fromNodeId,
sourceHandle: isTarget ? handleId : fromHandleId, sourceHandle: isTarget ? handleId : fromHandleId,
target: isTarget ? fromNodeId : handle.nodeId, target: isTarget ? fromNodeId : handleNodeId,
targetHandle: isTarget ? fromHandleId : handleId, targetHandle: isTarget ? fromHandleId : handleId,
} }
result.connection = connection result.connection = connection
result.handleId = handleId result.handleId = handleId
const isConnectable = connectable && connectableEnd
// in strict mode we don't allow target to target or source to source connections // in strict mode we don't allow target to target or source to source connections
const isValid = const isValid =
handleToCheck.classList.contains('connectable') && isConnectable &&
(connectionMode === ConnectionMode.Strict (connectionMode === ConnectionMode.Strict
? (isTarget && handle.type === 'source') || (!isTarget && handle.type === 'target') ? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')
: handleNodeId !== fromNodeId || handleId !== fromHandleId) : handleNodeId !== fromNodeId || handleId !== fromHandleId)
if (isValid) { if (isValid) {