xyflow / xyflow

React Flow | Svelte Flow - Powerful open source libraries for building node-based UIs with React (https://reactflow.dev) or Svelte (https://svelteflow.dev). Ready out-of-the-box and infinitely customizable.
https://xyflow.com
MIT License
23.43k stars 1.53k forks source link

Drag to add new node example don't work on touch screen #3711

Open bevinhex opened 8 months ago

bevinhex commented 8 months ago

Describe the Bug

the "add-node-on-edge-drop" example don't work on touch screen, it works on mouse drag and drop event, but not in touch screen

Your Example Website or App

https://reactflow.dev/examples/nodes/add-node-on-edge-drop

Steps to Reproduce the Bug or Issue

Expected behavior

new node should be created

Screenshots or Videos

Peek 2023-12-10 14-27

Platform

Additional context

No response

bilogic commented 4 months ago

Any roadmap to a fix?

dusty-phillips commented 1 month ago

This is also an issue on the svelte-based docs. I tried to work around it by enabling the dragdroptouch polyfill but I haven't been able to get it to trigger the drop events on the SvelteFlow component.

Edit: I've solved this by using the Neodrag library. I don't love the solution because the drop handler is on the source widget now. So I needed to put a bind:this on the container holding the svelte-flow and then put that in a context so I could use getClientBoundingRect to determine if the drop event overlaps the SvelteFlow container.

Feature Request: If the useFlow hook exposed a function to get the flow's boundingClientRect, this would be a lot tidier.

Here's a snippet of my code using Neodrag:

<script>
  import { draggable, type DragEventData } from '@neodrag/svelte'
  import { addTagMapNode } from '$lib/Db/mutations/tagMaps'

  export let tag

  const { svelteFlowContainer } = getContext(TAG_MAP_CONTEXT)
  let dragPosition = { x: 0, y: 0 }

  function onDragEnd(event) {
    const svelteFlowBounds = $svelteFlowContainer.getBoundingClientRect()
    const dropBounds = event.detail.rootNode.getBoundingClientRect()

    if (
      dropBounds.right < svelteFlowBounds.left ||
      dropBounds.left > svelteFlowBounds.right ||
      dropBounds.bottom < svelteFlowBounds.top ||
      dropBounds.top > svelteFlowBounds.bottom
    ) {
      dragPosition = { x: 0, y: 0 }
      return
    }

    const flowCoords = screenToFlowPosition(event.detail.rootNode.getBoundingClientRect())
    addTagMapNode(tag.id, flowCoords.x, flowCoords.y)
  }
</script>

<button
  use:draggable={{ position: dragPosition }}
  on:neodrag:end={onDragEnd}
>
  {name}
</button>